您现在的位置是:首页 >技术交流 >C# - 图片抠像 - RVM - 含模型 - 完整可运行网站首页技术交流
C# - 图片抠像 - RVM - 含模型 - 完整可运行
简介C# - 图片抠像 - RVM - 含模型 - 完整可运行
环境
.NET Framework 4.6.2 , X64 , VS2022
依赖
OpenCvSharp.dll,OpenCvSharp.Extensions.dll,Microsoft.ML.OnnxRuntime.dll,rvm_resnet50_fp32.onnx
效果
页面
全部逻辑代码
public partial class Form1 : Form
{
private string imgFile = "";
private int process_wd = 360;
private int process_ht = 640;
private InferenceSession session;
private static readonly SimpleObjectPool<List<NamedOnnxValue>> _inputsPool =
new SimpleObjectPool<List<NamedOnnxValue>>(() => new List<NamedOnnxValue>());
private static DenseTensor<float> _emptyTensor;
private static DenseTensor<float> _downsampleRatio;
private static Mat _resizedMat;
private static Mat _normalizedMat;
private static Mat[] _channels;
private static DenseTensor<float> _preprocessTensor;
private static float[] _channelData = new float[0];
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Filter = "图像文件|*.jpg;*.png;";
if (ofd.ShowDialog() == DialogResult.OK)
{
imgFile = ofd.FileName;
}
}
if (string.IsNullOrEmpty(imgFile))
{
return;
}
do_rec();
}
private async void do_rec()
{
var imgBs = File.ReadAllBytes(imgFile);
var imgInit = Image.FromStream(new MemoryStream(imgBs)) as Bitmap;
pb_init.Image = imgInit;
Application.DoEvents();
if (session == null)
{
load_removebg();
}
var imgRst = await Task.Run(() =>
removebg(imgBs)
);
pb_rst.Image = imgRst;
Application.DoEvents();
}
private void load_removebg()
{
session = new InferenceSession(AppDomain.CurrentDomain.BaseDirectory + "model\rvm_resnet50_fp32.onnx");
}
private Bitmap removebg(byte[] imgbs)
{
var image = Cv2.ImDecode(imgbs, ImreadModes.Color);
try
{
if (_emptyTensor == null)
{
_emptyTensor = new DenseTensor<float>(new[] { 1, 1, 1, 1 });
_downsampleRatio = new DenseTensor<float>(new[] { 1 });
_downsampleRatio.Buffer.Span[0] = 1f;
}
var inputs = _inputsPool.Get();
try
{
var input = PreprocessFrame(image);
inputs.Add(NamedOnnxValue.CreateFromTensor("src", input));
inputs.Add(NamedOnnxValue.CreateFromTensor("downsample_ratio", _downsampleRatio));
inputs.Add(NamedOnnxValue.CreateFromTensor("r1i", _emptyTensor));
inputs.Add(NamedOnnxValue.CreateFromTensor("r2i", _emptyTensor));
inputs.Add(NamedOnnxValue.CreateFromTensor("r3i", _emptyTensor));
inputs.Add(NamedOnnxValue.CreateFromTensor("r4i", _emptyTensor));
var outputs = session.Run(inputs);
var fgr = outputs.First(x => x.Name == "fgr").AsEnumerable<float>().ToArray();
var pha = outputs.First(x => x.Name == "pha").AsEnumerable<float>().ToArray();
return PostprocessFrame(image, fgr, pha).ToBitmap();
}
finally
{
inputs.Clear();
_inputsPool.Return(inputs);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in ProcessFrame: {ex.Message}");
Console.WriteLine($"Stack trace: {ex.StackTrace}");
throw;
}
}
private Tensor<float> PreprocessFrame(Mat frame)
{
try
{
{
process_wd = 512;
process_ht = (int)Math.Round(frame.Height / (double)frame.Width * process_wd);
_channelData = new float[process_ht * process_wd];
_resizedMat = new Mat();
_normalizedMat = new Mat();
_channels = new Mat[3];
_preprocessTensor = new DenseTensor<float>(new[] { 1, 3, process_ht, process_wd });
}
Cv2.Resize(frame, _resizedMat, new OpenCvSharp.Size(process_wd, process_ht));
_resizedMat.ConvertTo(_normalizedMat, MatType.CV_32F, 1.0 / 255.0);
Cv2.Split(_normalizedMat, out _channels);
var tensorSpan = _preprocessTensor.Buffer.Span;
unsafe
{
for (int c = 0; c < 3; c++)
{
Marshal.Copy(_channels[2 - c].Ptr(0), _channelData, 0, _channelData.Length);
int channelOffset = c * process_ht * process_wd;
fixed (void* channelDataPtr = &_channelData[0])
{
var floatPtr = (float*)channelDataPtr;
for (int i = 0; i < process_ht * process_wd; i++)
{
tensorSpan[channelOffset + i] = floatPtr[i];
}
}
}
}
return _preprocessTensor;
}
catch (Exception ex)
{
Console.WriteLine($"Error in PreprocessFrame: {ex.Message}");
Console.WriteLine($"Stack trace: {ex.StackTrace}");
throw;
}
}
private Mat PostprocessFrame(Mat original, float[] fgr, float[] pha)
{
try
{
using (var fgrMat = new Mat(process_ht, process_wd, MatType.CV_32FC3))
using (var phaMat = new Mat(process_ht, process_wd, MatType.CV_32FC1))
{
unsafe
{
fixed (float* fgrPtr = fgr)
fixed (float* phaPtr = pha)
{
using (var tempFgr = new Mat(process_ht, process_wd, MatType.CV_32FC3, (IntPtr)fgrPtr))
using (var tempPha = new Mat(process_ht, process_wd, MatType.CV_32FC1, (IntPtr)phaPtr))
{
tempFgr.CopyTo(fgrMat);
tempPha.CopyTo(phaMat);
}
}
}
using (var fgr8U = new Mat())
using (var pha8U = new Mat())
{
fgrMat.ConvertTo(fgr8U, MatType.CV_8UC3, 255.0);
phaMat.ConvertTo(pha8U, MatType.CV_8UC1, 255.0);
var result = new Mat(new OpenCvSharp.Size(process_wd, process_ht), MatType.CV_8UC3);
using (var resizedOriginal = new Mat())
using (var alpha3C = new Mat())
using (var inverseAlpha3C = new Mat())
using (var bgMat = new Mat(process_ht, process_wd, MatType.CV_8UC3, new Scalar(0, 255, 0))) // 绿色背景
{
Cv2.Resize(original, resizedOriginal, new OpenCvSharp.Size(process_wd, process_ht));
Cv2.Merge(new[] { pha8U, pha8U, pha8U }, alpha3C);
alpha3C.ConvertTo(alpha3C, MatType.CV_32FC3, 1.0 / 255.0);
Cv2.Subtract(new Scalar(1.0, 1.0, 1.0), alpha3C, inverseAlpha3C);
Cv2.Multiply(resizedOriginal, alpha3C, resizedOriginal, 1.0, MatType.CV_8UC3);
Cv2.Multiply(bgMat, inverseAlpha3C, bgMat, 1.0, MatType.CV_8UC3);
Cv2.Add(resizedOriginal, bgMat, result);
}
return result;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in PostprocessFrame: {ex.Message}");
Console.WriteLine($"Stack trace: {ex.StackTrace}");
throw;
}
}
}
public class SimpleObjectPool<T>
{
private readonly ConcurrentBag<T> _objects;
private readonly Func<T> _objectGenerator;
public SimpleObjectPool(Func<T> objectGenerator)
{
_objects = new ConcurrentBag<T>();
_objectGenerator = objectGenerator;
}
public T Get()
{
return _objects.TryTake(out T item) ? item : _objectGenerator();
}
public void Return(T item)
{
_objects.Add(item);
}
}
Demo 下载地址:
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。