C# OnnxRuntime 部署 RMBG-2.0 实现高精度背景去除
目录说明RMBG-2.0 是什么BiRefNet 架构的核心思想效果模型信息项目代码下载模型下载说明背景去除是图像处理中的一个经典难题。从早期的颜色键控、GrabCut到如今基于深度学习的分割模型技术的演进让抠图这件事变得越来越智能。而在众多背景去除方案中BRIA AI 开源的 RMBG-2.0 凭借其极高的精度和良好的工程化能力成为当前这一领域备受关注的选择。本文将介绍如何在 C# 中使用 ONNX Runtime 部署 RMBG-2.0 模型实现高精度的图像背景去除输出带透明通道的 PNG 图片。全文包含完整的代码实现适合希望将 AI 抠图能力集成到 .NET 应用中的开发者参考。RMBG-2.0 是什么RMBG-2.0Remove Background 2.0是 BRIA AI 推出的新一代图像背景移除模型基于 BiRefNetBilateral Reference Network双边参考网络架构设计。相比前代 RMBG v1.4准确率从 73.94% 大幅提升至 90.14%超越了不少商业付费工具BiRefNet 架构的核心思想传统图像分割模型往往把任务简化为“给每个像素打标签”——是前景就是 1是背景就是 0。这种单向分类思维在处理发丝、纱巾、玻璃反光等边界模糊区域时天然存在歧义。BiRefNet 换了一种思路它不直接预测分割图而是构建一个双向参考系统——前景参考分支聚焦于主体内部结构背景参考分支同步分析周围环境两个分支在特征空间进行交叉调制共同完成高保真分割。具体来说BiRefNet 由两个核心模块构成定位模块Localization Module, LM 负责理解全局语义、生成语义图恢复模块Restoration Module, RM 负责边缘细节的精修通过边缘感知注意力机制实现对发丝级细节的精细处理。这种设计使得 RMBG-2.0 在保持计算效率的同时能够精准处理复杂边缘。效果模型信息Model Properties----------------------------------------------------------------------------------------Inputs-------------------------namepixel_valuestensorFloat[1, 3, -1, -1]---------------------------------------------------------------Outputs-------------------------namealphastensorFloat[1, 1, -1, -1]---------------------------------------------------------------项目代码using Microsoft.ML.OnnxRuntime;using Microsoft.ML.OnnxRuntime.Tensors;using OpenCvSharp;using System;using System.Collections.Generic;using System.Drawing;using System.Drawing.Imaging;using System.Linq;using System.Windows.Forms;namespace Onnx_Demo{public partial class Form1 : Form{public Form1(){InitializeComponent();}string fileFilter *.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png;string image_path ;string startupPath;DateTime dt1 DateTime.Now;DateTime dt2 DateTime.Now;string model_path;Mat image; // 原始图像BGRMat result_image_with_alpha; // 最终带有透明背景的图像SessionOptions options;InferenceSession onnx_session;Tensorfloat input_tensor;ListNamedOnnxValue input_container;IDisposableReadOnlyCollectionDisposableNamedOnnxValue result_infer;int inpHeight, inpWidth;// RMBG-2.0 预处理参数private readonly float[] mean new float[] { 0.485f, 0.456f, 0.406f };private readonly float[] std new float[] { 0.229f, 0.224f, 0.225f };private void button1_Click(object sender, EventArgs e){OpenFileDialog ofd new OpenFileDialog();ofd.Filter fileFilter;if (ofd.ShowDialog() ! DialogResult.OK) return;pictureBox1.Image null;image_path ofd.FileName;pictureBox1.Image new Bitmap(image_path);textBox1.Text ;image new Mat(image_path);pictureBox2.Image null;}private void button2_Click(object sender, EventArgs e){if (image_path ){return;}button2.Enabled false;pictureBox2.Image null;textBox1.Text ;Application.DoEvents();// 读取原始图像BGRimage new Mat(image_path);int originalWidth image.Cols;int originalHeight image.Rows;// ------------------ 预处理 ------------------// 1. 转换为RGBMat rgb new Mat();Cv2.CvtColor(image, rgb, ColorConversionCodes.BGR2RGB);// 2. Resize到模型输入尺寸1024x1024Mat resized new Mat();Cv2.Resize(rgb, resized, new OpenCvSharp.Size(inpWidth, inpHeight));// 3. 转换为浮点并归一化到 [0,1]resized.ConvertTo(resized, MatType.CV_32FC3, 1.0 / 255.0);// 4. 分离通道并应用标准化 (value - mean) / stdMat[] channels Cv2.Split(resized); // R, G, Bfloat[] inputData new float[3 * inpHeight * inpWidth];int channelSize inpHeight * inpWidth;for (int c 0; c 3; c){float[] channelData new float[channelSize];System.Runtime.InteropServices.Marshal.Copy(channels[c].Data, channelData, 0, channelSize);// 标准化每个通道for (int i 0; i channelSize; i){channelData[i] (channelData[i] - mean[c]) / std[c];}Array.Copy(channelData, 0, inputData, c * channelSize, channelSize);}// 创建输入张量 (1, 3, H, W)input_tensor new DenseTensorfloat(inputData, new[] { 1, 3, inpHeight, inpWidth });// 将输入放入容器使用正确的输入名称 pixel_valuesinput_container.Clear();input_container.Add(NamedOnnxValue.CreateFromTensor(pixel_values, input_tensor));// ------------------ 推理 ------------------dt1 DateTime.Now;result_infer onnx_session.Run(input_container);dt2 DateTime.Now;// 按输出名称 alphas 获取结果var output result_infer.First(x x.Name alphas).AsTensorfloat();int[] outShape output.Dimensions.ToArray();int outH outShape[2];int outW outShape[3];float[] predFloat output.ToArray().Select(x (float)x).ToArray();// 创建单通道 MatAlpha 蒙版值域 [0,1]Mat alphaMat new Mat(outH, outW, MatType.CV_32FC1, predFloat);// ------------------ 后处理 ------------------// 1. 双线性插值到原始尺寸Mat maskResized new Mat();Cv2.Resize(alphaMat, maskResized, new OpenCvSharp.Size(originalWidth, originalHeight), interpolation: InterpolationFlags.Linear);// 2. 确保值在 [0,1] 范围内sigmoid输出理论如此防止溢出Cv2.Threshold(maskResized, maskResized, 1.0, 1.0, ThresholdTypes.Trunc);Cv2.Threshold(maskResized, maskResized, 0.0, 0.0, ThresholdTypes.Tozero);// 3. 转换为8位单通道alpha 0~255Mat alphaMask new Mat();maskResized.ConvertTo(alphaMask, MatType.CV_8UC1, 255.0);// ------------------ 合成透明背景图像 ------------------// 原始图像BGR转为 BGRAMat rgba new Mat();Cv2.CvtColor(image, rgba, ColorConversionCodes.BGR2BGRA);// 替换 alpha 通道Mat[] bgraChannels Cv2.Split(rgba);bgraChannels[3] alphaMask;Cv2.Merge(bgraChannels, rgba);result_image_with_alpha rgba.Clone();// 显示最终图像PictureBox 支持透明通道显示pictureBox2.Image new Bitmap(rgba.ToMemoryStream());textBox1.Text 推理耗时: (dt2 - dt1).TotalMilliseconds ms;button2.Enabled true;}private void Form1_Load(object sender, EventArgs e){startupPath System.Windows.Forms.Application.StartupPath;model_path model/model.onnx; // 请确保模型文件存在于此路径// 创建会话使用 CPU可根据需要改为 CUDAoptions new SessionOptions();options.LogSeverityLevel OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO;options.AppendExecutionProvider_CPU(0);onnx_session new InferenceSession(model_path, options);input_container new ListNamedOnnxValue();// 模型固定输入尺寸inpHeight 1024;inpWidth 1024;// 测试图片路径可选image_path test_img/1.jpg;if (System.IO.File.Exists(image_path)){pictureBox1.Image new Bitmap(image_path);image new Mat(image_path);}}private void pictureBox1_DoubleClick(object sender, EventArgs e){Common.ShowNormalImg(pictureBox1.Image);}private void pictureBox2_DoubleClick(object sender, EventArgs e){Common.ShowNormalImg(pictureBox2.Image);}SaveFileDialog sdf new SaveFileDialog();private void button3_Click(object sender, EventArgs e){if (result_image_with_alpha null || result_image_with_alpha.Empty()){MessageBox.Show(请先进行推理);return;}sdf.Title 保存透明背景图片;sdf.Filter PNG图片 (*.png)|*.png|JPEG图片 (*.jpg)|*.jpg|BMP图片 (*.bmp)|*.bmp;sdf.FilterIndex 1; // 默认 PNG保留透明度if (sdf.ShowDialog() DialogResult.OK){string ext System.IO.Path.GetExtension(sdf.FileName).ToLower();ImageFormat format ImageFormat.Png;if (ext .jpg || ext .jpeg)format ImageFormat.Jpeg;else if (ext .bmp)format ImageFormat.Bmp;using (var stream result_image_with_alpha.ToMemoryStream())using (var bitmap new Bitmap(stream)){bitmap.Save(sdf.FileName, format);}MessageBox.Show(保存成功位置 sdf.FileName);}}}}using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Windows.Forms; namespace Onnx_Demo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } string fileFilter *.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png; string image_path ; string startupPath; DateTime dt1 DateTime.Now; DateTime dt2 DateTime.Now; string model_path; Mat image; // 原始图像BGR Mat result_image_with_alpha; // 最终带有透明背景的图像 SessionOptions options; InferenceSession onnx_session; Tensorfloat input_tensor; ListNamedOnnxValue input_container; IDisposableReadOnlyCollectionDisposableNamedOnnxValue result_infer; int inpHeight, inpWidth; // RMBG-2.0 预处理参数 private readonly float[] mean new float[] { 0.485f, 0.456f, 0.406f }; private readonly float[] std new float[] { 0.229f, 0.224f, 0.225f }; private void button1_Click(object sender, EventArgs e) { OpenFileDialog ofd new OpenFileDialog(); ofd.Filter fileFilter; if (ofd.ShowDialog() ! DialogResult.OK) return; pictureBox1.Image null; image_path ofd.FileName; pictureBox1.Image new Bitmap(image_path); textBox1.Text ; image new Mat(image_path); pictureBox2.Image null; } private void button2_Click(object sender, EventArgs e) { if (image_path ) { return; } button2.Enabled false; pictureBox2.Image null; textBox1.Text ; Application.DoEvents(); // 读取原始图像BGR image new Mat(image_path); int originalWidth image.Cols; int originalHeight image.Rows; // ------------------ 预处理 ------------------ // 1. 转换为RGB Mat rgb new Mat(); Cv2.CvtColor(image, rgb, ColorConversionCodes.BGR2RGB); // 2. Resize到模型输入尺寸1024x1024 Mat resized new Mat(); Cv2.Resize(rgb, resized, new OpenCvSharp.Size(inpWidth, inpHeight)); // 3. 转换为浮点并归一化到 [0,1] resized.ConvertTo(resized, MatType.CV_32FC3, 1.0 / 255.0); // 4. 分离通道并应用标准化 (value - mean) / std Mat[] channels Cv2.Split(resized); // R, G, B float[] inputData new float[3 * inpHeight * inpWidth]; int channelSize inpHeight * inpWidth; for (int c 0; c 3; c) { float[] channelData new float[channelSize]; System.Runtime.InteropServices.Marshal.Copy(channels[c].Data, channelData, 0, channelSize); // 标准化每个通道 for (int i 0; i channelSize; i) { channelData[i] (channelData[i] - mean[c]) / std[c]; } Array.Copy(channelData, 0, inputData, c * channelSize, channelSize); } // 创建输入张量 (1, 3, H, W) input_tensor new DenseTensorfloat(inputData, new[] { 1, 3, inpHeight, inpWidth }); // 将输入放入容器使用正确的输入名称 pixel_values input_container.Clear(); input_container.Add(NamedOnnxValue.CreateFromTensor(pixel_values, input_tensor)); // ------------------ 推理 ------------------ dt1 DateTime.Now; result_infer onnx_session.Run(input_container); dt2 DateTime.Now; // 按输出名称 alphas 获取结果 var output result_infer.First(x x.Name alphas).AsTensorfloat(); int[] outShape output.Dimensions.ToArray(); int outH outShape[2]; int outW outShape[3]; float[] predFloat output.ToArray().Select(x (float)x).ToArray(); // 创建单通道 MatAlpha 蒙版值域 [0,1] Mat alphaMat new Mat(outH, outW, MatType.CV_32FC1, predFloat); // ------------------ 后处理 ------------------ // 1. 双线性插值到原始尺寸 Mat maskResized new Mat(); Cv2.Resize(alphaMat, maskResized, new OpenCvSharp.Size(originalWidth, originalHeight), interpolation: InterpolationFlags.Linear); // 2. 确保值在 [0,1] 范围内sigmoid输出理论如此防止溢出 Cv2.Threshold(maskResized, maskResized, 1.0, 1.0, ThresholdTypes.Trunc); Cv2.Threshold(maskResized, maskResized, 0.0, 0.0, ThresholdTypes.Tozero); // 3. 转换为8位单通道alpha 0~255 Mat alphaMask new Mat(); maskResized.ConvertTo(alphaMask, MatType.CV_8UC1, 255.0); // ------------------ 合成透明背景图像 ------------------ // 原始图像BGR转为 BGRA Mat rgba new Mat(); Cv2.CvtColor(image, rgba, ColorConversionCodes.BGR2BGRA); // 替换 alpha 通道 Mat[] bgraChannels Cv2.Split(rgba); bgraChannels[3] alphaMask; Cv2.Merge(bgraChannels, rgba); result_image_with_alpha rgba.Clone(); // 显示最终图像PictureBox 支持透明通道显示 pictureBox2.Image new Bitmap(rgba.ToMemoryStream()); textBox1.Text 推理耗时: (dt2 - dt1).TotalMilliseconds ms; button2.Enabled true; } private void Form1_Load(object sender, EventArgs e) { startupPath System.Windows.Forms.Application.StartupPath; model_path model/model.onnx; // 请确保模型文件存在于此路径 // 创建会话使用 CPU可根据需要改为 CUDA options new SessionOptions(); options.LogSeverityLevel OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO; options.AppendExecutionProvider_CPU(0); onnx_session new InferenceSession(model_path, options); input_container new ListNamedOnnxValue(); // 模型固定输入尺寸 inpHeight 1024; inpWidth 1024; // 测试图片路径可选 image_path test_img/1.jpg; if (System.IO.File.Exists(image_path)) { pictureBox1.Image new Bitmap(image_path); image new Mat(image_path); } } private void pictureBox1_DoubleClick(object sender, EventArgs e) { Common.ShowNormalImg(pictureBox1.Image); } private void pictureBox2_DoubleClick(object sender, EventArgs e) { Common.ShowNormalImg(pictureBox2.Image); } SaveFileDialog sdf new SaveFileDialog(); private void button3_Click(object sender, EventArgs e) { if (result_image_with_alpha null || result_image_with_alpha.Empty()) { MessageBox.Show(请先进行推理); return; } sdf.Title 保存透明背景图片; sdf.Filter PNG图片 (*.png)|*.png|JPEG图片 (*.jpg)|*.jpg|BMP图片 (*.bmp)|*.bmp; sdf.FilterIndex 1; // 默认 PNG保留透明度 if (sdf.ShowDialog() DialogResult.OK) { string ext System.IO.Path.GetExtension(sdf.FileName).ToLower(); ImageFormat format ImageFormat.Png; if (ext .jpg || ext .jpeg) format ImageFormat.Jpeg; else if (ext .bmp) format ImageFormat.Bmp; using (var stream result_image_with_alpha.ToMemoryStream()) using (var bitmap new Bitmap(stream)) { bitmap.Save(sdf.FileName, format); } MessageBox.Show(保存成功位置 sdf.FileName); } } } }下载源码下载模型下载通过网盘分享的文件RMBG-2.0 模型链接: https://pan.baidu.com/s/12pA3YBoDQqVEEO-PkDBg8w?pwdtqj7 提取码: tqj7
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2501708.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!