C# OnnxRuntime 部署 DAViD 软前景分割

张开发
2026/4/19 6:20:09 15 分钟阅读

分享文章

C# OnnxRuntime 部署 DAViD  软前景分割
说明官网地址https://github.com/microsoft/DAViD模型下载效果模型信息Model Properties ------------------------- metadata{} --------------------------------------------------------------- Inputs ------------------------- nameinput tensorFloat[-1, 3, 512, 512] --------------------------------------------------------------- Outputs ------------------------- nameoutput tensorFloat[-1, 1, 512, 512] ---------------------------------------------------------------项目代码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;*.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; // DAViD 模型二值化阈值默认0不二值化输出软掩膜 private float binarizationThreshold 0f; // ----- 按钮选择图片 ----- 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 (string.IsNullOrEmpty(image_path)) { MessageBox.Show(请先选择图片); return; } binarizationThreshold 0.0f; 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. 直接缩放 BGR 图像至模型输入尺寸 (512x512) Mat resized new Mat(); Cv2.Resize(image, resized, new OpenCvSharp.Size(inpWidth, inpHeight)); // 2. 转换为浮点型并归一化到 [0, 1] resized.ConvertTo(resized, MatType.CV_32FC3, 1.0 / 255.0); // 3. 分离 BGR 通道Split 顺序为 B, G, R Mat[] channels Cv2.Split(resized); int channelSize inpHeight * inpWidth; float[] inputData new float[3 * channelSize]; for (int c 0; c 3; c) { float[] channelData new float[channelSize]; System.Runtime.InteropServices.Marshal.Copy(channels[c].Data, channelData, 0, channelSize); // 直接复制已归一化的像素值无需额外处理 Array.Copy(channelData, 0, inputData, c * channelSize, channelSize); } // 4. 创建输入张量 (N, C, H, W) input_tensor new DenseTensorfloat(inputData, new[] { 1, 3, inpHeight, inpWidth }); input_container.Clear(); input_container.Add(NamedOnnxValue.CreateFromTensor(input, input_tensor)); // ------------------ 推理 ------------------ dt1 DateTime.Now; result_infer onnx_session.Run(input_container); dt2 DateTime.Now; // 获取输出模型输出名称为 output形状 [1, 1, 512, 512] var output result_infer.First(x x.Name output).AsTensorfloat(); int[] outShape output.Dimensions.ToArray(); int outH outShape[2]; int outW outShape[3]; float[] predFloat output.ToArray(); // 已经是 float // 创建单通道 Mat (CV_32FC1)值域 [0,1] Mat softMask new Mat(outH, outW, MatType.CV_32FC1, predFloat); // ------------------ 后处理 ------------------ // 1. 双线性插值至原始尺寸 Mat maskResized new Mat(); Cv2.Resize(softMask, maskResized, new OpenCvSharp.Size(originalWidth, originalHeight), interpolation: InterpolationFlags.Linear); // 2. 限制值域在 [0,1]防止数值误差 //maskResized.SetTo(0, maskResized.LessThan(0)); //maskResized.SetTo(1, maskResized.GreaterThanOrEqual(1)); //Cv2.Threshold(maskResized, maskResized, 1.0, 1.0, ThresholdTypes.Trunc); //Cv2.Threshold(maskResized, maskResized, 0.0, 0.0, ThresholdTypes.Tozero); Mat finalAlpha; if (binarizationThreshold 0) { // 二值化大于阈值设为1其余为0 Mat binaryMask new Mat(maskResized.Size(), MatType.CV_32FC1, 0.0f); Cv2.Threshold(maskResized, binaryMask, binarizationThreshold, 1.0, ThresholdTypes.Binary); finalAlpha binaryMask; } else { finalAlpha maskResized; } // 转换为 8 位单通道 (0~255) 用于 alpha 合成 Mat alphaMask new Mat(); finalAlpha.ConvertTo(alphaMask, MatType.CV_8UC1, 255.0); // ------------------ 合成透明背景图像 ------------------ Mat rgba new Mat(); Cv2.CvtColor(image, rgba, ColorConversionCodes.BGR2BGRA); Mat[] bgraChannels Cv2.Split(rgba); bgraChannels[3] alphaMask; Cv2.Merge(bgraChannels, rgba); result_image_with_alpha rgba.Clone(); // 显示结果注意PictureBox 默认不支持透明但保存 PNG 时有效 pictureBox2.Image new Bitmap(rgba.ToMemoryStream()); textBox1.Text $推理耗时: {(dt2 - dt1).TotalMilliseconds:F2} ms; button2.Enabled true; } // ----- 窗体加载初始化模型 ----- private void Form1_Load(object sender, EventArgs e) { startupPath Application.StartupPath; // 请根据实际模型路径修改模型输入尺寸应为 512x512 model_path System.IO.Path.Combine(startupPath, model, foreground-segmentation-model-vitb16_384.onnx); if (!System.IO.File.Exists(model_path)) { MessageBox.Show($模型文件不存在: {model_path}); return; } options new SessionOptions(); options.LogSeverityLevel OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO; options.AppendExecutionProvider_CPU(0); // 若需 CUDA 支持请取消注释并安装对应运行库 // options.AppendExecutionProvider_CUDA(0); onnx_session new InferenceSession(model_path, options); input_container new ListNamedOnnxValue(); // 模型固定输入尺寸 (DAViD 为 512x512) inpHeight 512; inpWidth 512; // 可选默认测试图片 string testImg System.IO.Path.Combine(startupPath, test_img, 1.jpg); if (System.IO.File.Exists(testImg)) { image_path testImg; 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; 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; elseif (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}); } } } }

更多文章