/*
最近接个小活,甲方想做一个互动程序,需要把人像抠出来。我查了一圈资料,有阿里腾讯百度的云平台都提供这样的接口,不过都需要联网才能使用,没法满足我的实际需求。虽然有离线部署的选项,但是应该不是我这样的个人能申请到的。
然后,我发现paddle上面有个这样的功能。
*/
Python部分
import paddle
import paddlehub as hub
from PIL import Image, ImageSequence
import numpy as np
import os
input_path = 'humanseg_input\\'
out_path = 'output\\'
paddle.enable_static()
module = hub.Module(name="deeplabv3p_xception65_humanseg")
while True :
print("input")
files = input()
strs = files.split('|')
img_path = [input_path + img for img in strs]
input_dict = {"image": img_path,'output_dir':out_path}
results = module.segmentation(data=input_dict)
这里面安装的时候需要注意几个点
1、python3.10是跑不了的,有几个依赖再安装时会报错
2、我用3.9的python跑,发现import paddlehub时会报一个json解析的错误,经过排查,发现是在解析一个config.json文件时,文件里的内容是空的,经百度,解决如下:找到用户文件夹/.paddlehub/conf/config.json,把如下内容写入文件。
{ "server_url": [ "http://paddlepaddle.org.cn/paddlehub" ], "resource_storage_server_url": "https://bj.bcebos.com/paddlehub-data/", "debug": false, "log_level": "DEBUG" }
3.模块deeplabv3p_xception65_humanseg如果用最新的,返回的数据结构会不一样,需指定版本。用到关键组件和版本如下:
pip install PaddlePaddle pip install paddlehub==1.6.0 hub install deeplabv3p_xception65_humanseg==1.0.0
Unity 部分
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using UnityEngine;
public class LocalImageHandler : MonoBehaviour
{
//python文件所在的目录
private string pythonCmdDir = @"C:\Users\HuMingHao\Desktop\HumanSeg抠图\";
private string humanseg_input = "humanseg_input";
private string humanseg_output = "humanseg_output";
//系统cmd控制台路径
private string CmdPath = @"C:\Windows\System32\cmd.exe";
private string startCmd = "python humanseg.py";
private void RunCmd()
{
process = new Process();
process.StartInfo.StandardOutputEncoding = Encoding.GetEncoding("gb2312");
process.StartInfo.FileName = CmdPath;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WorkingDirectory = pythonCmdDir;
process.Start();//启动程序
//向cmd窗口写入命令
process.StandardInput.WriteLine(startCmd);
while (true)
{
//获取cmd窗口的输出信息
string output = process.StandardOutput.ReadLine();
if (output == "input")
READY = true;
Thread.Sleep(500);
}
}
private void OnDestroy()
{
if (cmdThread != null)
{
cmdThread.Abort();
}
if (process != null && process.HasExited == false)
{
process.Close();
}
}
Process process;
Thread cmdThread;
public static LocalImageHandler instance;
public bool READY = false;
private void Awake()
{
instance = this;
READY = false;
cmdThread = new Thread(new ThreadStart(RunCmd));
cmdThread.Start();
}
public void BeginHumanSeg(Texture2D tex,Action<Texture2D> callback)
{
if (READY == true)
{
READY = false;
StartCoroutine(HumanSegCor(tex,callback));
}
}
IEnumerator HumanSegCor(Texture2D tex,Action<Texture2D> callback)
{
string tempFileName = DateTime.Now.Ticks + ".png";
byte[] imgdata = tex.EncodeToPNG();
File.WriteAllBytes(pythonCmdDir + humanseg_input + "\\" + tempFileName, imgdata);
process.StandardInput.WriteLine(tempFileName);
while (!READY)
{
yield return new WaitForEndOfFrame();
}
byte[] outdata = File.ReadAllBytes(pythonCmdDir + humanseg_output + "\\" + tempFileName);
Texture2D handledTex = new Texture2D(128, 128);
handledTex.LoadImage(outdata);
callback(handledTex);
}
}
测试代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class test : MonoBehaviour {
public Texture2D source;
public RawImage imgTarget;
private void OnGUI()
{
if (GUILayout.Button("handle image"))
{
LocalImageHandler.instance.BeginHumanSeg(source, (tex) =>
{
imgTarget.texture = tex;
});
}
}
}