恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

C#调用ONNX版Segment Anything实现工业级一键抠图

  • 首页
  • 资讯中心
  • /
  • C#调用ONNX版Segment Anything实现工业级一键抠图

相关资讯

Agent-Native架构实践:从AI增强到智能体驱动的系统重构指南 2026/9/26 6:36:58
“cua”热梗撞上CUDA:从网络用语到并行计算实战解析 2026/9/26 6:36:58
分布式鲁棒优化与联合机会约束的电力调度MATLAB实现 2026/9/26 6:31:58

最新资讯

OpenRouter Batch API批量推理半价实战:异步批处理省钱指南
Claude Code 模板工程化:用 CLAUDE.md 与指令模板固化高效工作流
OpenRouter Batch API 批量推理实战:半价成本与工程化避坑指南
A-MLE智能体框架:广告排序模型自动化实验实战指南
BGE-M3文本嵌入模型实战:RAG检索增强生成中的部署、调优与避坑指南
输入增量实现状态空间MPC:Matlab公式推导与工程实践

今日推荐

麒麟Kylin V10 SP3服务器安装实战:硬件兼容、启动优化与生产级分区
华为手机助手导致Windows内存完整性关闭的根因与修复
图书馆图书借阅管理系统:JSP+Servlet+MySQL源码部署与答辩指南

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

C#调用ONNX版Segment Anything实现工业级一键抠图

发布时间:2026/9/26 6:36:58
C#调用ONNX版Segment Anything实现工业级一键抠图 简介本资源是基于C#实现的ONNX版Segment Anything ModelSAM图像分割项目面向Windows平台开发者与计算机视觉初学者解决传统抠图工具操作繁琐、精度不足的问题支持一键自动提取图像主体并生成透明背景蒙版。压缩包共301个文件含64个运行依赖DLL、40个XML配置与文档、26个说明文本、12个核心C#源码文件及2个ONNX模型文件配合Visual Studio解决方案.sln和NuGet包管理结构开箱即用。资源包大小为610.27MB结构清晰涵盖预处理、ONNX Runtime推理、结果后处理及WinForms图形界面全流程代码。目前已有3343人学习下载读者可直接复现完整的一键抠图功能深入理解C#调用ONNX模型的工程实践、图像张量预处理逻辑、分割掩码解析方法并获得可二次开发的模块化代码架构与调试友好的项目组织方式。1. C# 调用 ONNX 版 Segment Anything 实现本地“分割万物”不是 Demo是能进产线的一键抠图管线你手头有一张产品白底图要自动抠出主体发给电商上架或者产线摄像头拍到一堆混杂零件需要实时框出每个部件做尺寸测量又或者医疗影像里要快速圈出病灶区域供医生复核——这些场景过去得靠标注团队花半天调 Mask R-CNN 参数或让算法同事临时改 PyTorch 推理脚本。但现在C# Onnx segment-anything 分割万物 一键抠图 源码这个组合意味着你在 Windows 工控机、WPF 上位机、甚至 .NET 6 的 Linux 容器里不用装 Python 环境、不依赖 CUDA 驱动、不碰 conda只靠一个.onnx模型文件 几百行 C# 代码就能把 SAMSegment Anything Model的零样本分割能力真正落地成可部署、可调试、可集成进现有工业软件的模块。这不是 Jupyter Notebook 里的炫技而是我去年在三个客户现场反复打磨出来的路径模型量化压缩到 120MB 以内、CPU 推理单图耗时压到 800msi5-10400、支持鼠标点选/框选/多点提示三种交互模式、输出带 Alpha 通道的 PNG 可直接喂给下游渲染引擎。如果你正在用 C# 做视觉类上位机、质检系统或数字孪生前端这篇就是你跳过 Python 中间层、直连最新开源分割能力的实操地图。2. 为什么选 ONNX C# 而不是 Python PyTorch——从部署约束反推技术选型2.1 工业现场的真实约束倒逼架构决策很多工程师看到 “Segment Anything” 第一反应是跑 Hugging Face 的transformerssam库但实际进厂调试时会立刻撞墙环境不可控客户工控机预装 Win10 LTSC禁止安装 Python、pip、甚至 PowerShell 执行策略被锁死依赖链太长PyTorch → CUDA → cuDNN → Visual C Redist → OpenMP任意一环版本不匹配就ImportError: DLL load failed内存与启动时间敏感上位机需 3 秒内响应操作而torch.load()加载 3GB 模型 JIT 编译常卡 15 秒以上安全审计红线Python 脚本被判定为“不可信代码”而 .NET 程序集可通过强签名 GAC 注册通过等保二级审查。ONNX 成为关键破局点——它把 PyTorch 训练好的 SAM 模型如sam_vit_h.onnx编译成与框架无关的中间表示再用 Microsoft.ML.OnnxRuntime 这个纯 C 实现的推理引擎加载。该引擎✅ 支持 x64/x86/ARM64Windows/Linux/macOS 全平台✅ CPU 推理无需 GPU 驱动AVX2 指令集加速已内置✅ 单个Microsoft.ML.OnnxRuntime.dll约 8MB即可运行无外部 DLL 依赖✅ .NET Standard 2.0 兼容可无缝嵌入 WPF、WinForms、ASP.NET Core 或 Unity IL2CPP 环境。提示ONNX 并非万能。SAM 的 Prompt Encoder 和 Mask Decoder 有动态 shape如点数可变需用--dynamic_axes导出时显式声明否则 C# 加载会报InvalidArgument: Input is null。这点在 PyTorch → ONNX 转换阶段就必须处理不能等到 C# 里再 debug。2.2 从 PyTorch 到 ONNX三步导出 SAM 模型含避坑参数官方 SAM 仓库facebookresearch/segment-anything默认只提供.pth权重需自行导出 ONNX。不要直接用torch.onnx.export(model, ...)硬导——SAM 的forward方法含大量控制流if/else和动态张量拼接会触发 ONNX 不支持的算子。正确做法是复用 Meta 开源的export_onnx.py脚本位于segment-anything/segment_anything/utils/export_onnx.py并打补丁# export_onnx.py 关键修改修复动态 batch point 数 import torch from segment_anything import sam_model_registry from segment_anything.utils.onnx import SamOnnxModel # 1. 加载模型指定 vit_h对应 2.5GB pth sam sam_model_registry[vit_h](checkpointsam_vit_h_4b8939.pth) # 2. 包装为 ONNX 兼容 wrapper onnx_model SamOnnxModel(sam, return_single_maskTrue) # 3. 构造 dummy input —— 注意必须指定 dynamic batch 和 points dummy_inputs { image: torch.randn(1, 3, 1024, 1024, dtypetorch.float32), # 固定 size point_coords: torch.randint(0, 1024, (1, 2, 2), dtypetorch.float32), # batch1, num_points2 point_labels: torch.tensor([[1, 0]], dtypetorch.float32), # 1foreground, 0background orig_im_size: torch.tensor([1024, 1024], dtypetorch.int64), } # 4. 导出关键dynamic_axes 必须覆盖所有可变维度 torch.onnx.export( onnx_model, tuple(dummy_inputs.values()), sam_vit_h.onnx, input_nameslist(dummy_inputs.keys()), output_names[masks, iou_predictions, low_res_masks], dynamic_axes{ point_coords: {0: batch_size, 1: num_points}, # batch 和点数都可变 point_labels: {0: batch_size, 1: num_points}, masks: {0: batch_size, 1: num_masks}, iou_predictions: {0: batch_size, 1: num_masks}, low_res_masks: {0: batch_size, 1: num_masks}, }, opset_version17, # SAM 需要 opset 17支持 ScatterND 等 do_constant_foldingTrue, )参数说明opset_version17低于此版本会报Unsupported operator ScatterND因 SAM 的 Mask Decoder 大量使用该算子dynamic_axes必须声明point_coords和point_labels的第 1 维num_points可变否则 C# 传入 1 个点或 5 个点都会失败return_single_maskTrue关闭多掩码输出只返回 IoU 最高的 mask减少 C# 后处理逻辑orig_im_size必须作为输入传入ONNX 模型内部用它做坐标归一化反算漏掉则输出 mask 尺寸错乱。导出后用 Netron 打开sam_vit_h.onnx确认输入节点名与dummy_inputs一致image,point_coords,point_labels,orig_im_size且point_coords的 shape 显示为[batch_size, num_points, 2]—— 这是 C# 侧构造 Tensor 的依据。3. C# 侧 ONNX Runtime 初始化与预处理绕过浮点精度陷阱3.1 创建 Session选择 CPU 还是 DirectMLONNX Runtime 在 Windows 上支持多个 Execution ProviderEP选错会导致性能断崖CPUExecutionProvider最稳但 AVX2 优化需手动开启DirectMLExecutionProvider利用 DirectX 12 GPU 加速对 Intel 核显/NVIDIA GTX 显著提速实测 i7-11800H Iris Xe 下比 CPU 快 3.2xCUDAExecutionProvider需 NVIDIA 驱动 CUDA Toolkit工业现场极少具备。生产环境首选 DirectML兼容 Win10 1809初始化代码如下using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; // 创建 Session Options 并启用 DirectML var sessionOptions new SessionOptions(); sessionOptions.GraphOptimizationLevel GraphOptimizationLevel.ORT_ENABLE_EXTENDED; // 启用全部优化 sessionOptions.IntraOpNumThreads Environment.ProcessorCount / 2; // 避免线程争抢 // 关键优先尝试 DirectML失败则回退 CPU try { sessionOptions.AppendExecutionProvider_DirectML(0); // 设备 ID 0 } catch (Exception) { // DirectML 不可用时降级 sessionOptions.AppendExecutionProvider_CPU(); } // 加载模型注意路径必须是绝对路径相对路径在服务环境下常失效 var session new InferenceSession(sam_vit_h.onnx, sessionOptions);注意AppendExecutionProvider_DirectML(0)的0是设备索引多显卡时需用DirectML.GetAvailableDevices()枚举真实设备 ID硬写0在某些工控机如研华 AIMB-707上会初始化失败。3.2 图像预处理OpenCVSharp 与 System.Drawing 的精度博弈SAM 输入要求RGB 图像[H, W, 3]uint8缩放到1024x1024保持宽高比短边填充黑边归一化(pixel - [123.675, 116.28, 103.53]) / [58.395, 57.12, 57.375]ImageNet 标准转置为[3, H, W]float32。陷阱在于归一化常数精度PyTorch 默认用float32但 C#float计算若用double中间变量会引入1e-7级误差导致输出 mask 边缘出现噪点。必须全程用float// 使用 OpenCVSharp 预处理比 System.Drawing 更准且支持 SIMD using var src Cv2.ImRead(input.jpg); using var resized new Mat(); Cv2.Resize(src, resized, new Size(1024, 1024)); // 简单 resize实际应保持比例padding // 归一化OpenCVSharp 的 ConvertScaleAbs 无法做减法手动循环 var data resized.GetArrayfloat(); // 获取 float32 数据需先 cvtColor BGR-RGB var mean new[] { 123.675f, 116.28f, 103.53f }; var std new[] { 58.395f, 57.12f, 57.375f }; for (int i 0; i data.Length; i 3) { data[i 0] (data[i 0] - mean[0]) / std[0]; // R data[i 1] (data[i 1] - mean[1]) / std[1]; // G data[i 2] (data[i 2] - mean[2]) / std[2]; // B } // 转置 [H,W,3] - [3,H,W] var tensorData new float[3 * 1024 * 1024]; for (int y 0; y 1024; y) for (int x 0; x 1024; x) for (int c 0; c 3; c) { tensorData[c * 1024 * 1024 y * 1024 x] data[y * 1024 * 3 x * 3 c]; } // 构造 ONNX Tensorshape: [1,3,1024,1024] var imageTensor new DenseTensorfloat(tensorData, new int[] { 1, 3, 1024, 1024 });为什么不用 System.DrawingBitmap.LockBits返回byte*需手动转float易出错Graphics.DrawImage插值算法与 OpenCV 的INTER_AREA不一致缩放后图像细节丢失更严重无 SIMD 加速1024x1024 图像预处理慢 40%。实测 OpenCVSharp 4.8.1 DNN模块预处理耗时 120msSystem.Drawing 方案达 180ms且后者在 4K 屏下偶发OutOfMemoryException。4. C# 调用 ONNX Runtime 执行分割点选/框选双模式实现与后处理技巧4.1 构造 Prompt 输入点坐标与标签的 C# 表达SAM 的point_coords输入是[batch, num_points, 2]的 float32 Tensorpoint_labels是[batch, num_points]的 int64 Tensor。C# 中需严格按 ONNX 模型定义构造// 用户点击坐标假设窗体坐标系需转为归一化图像坐标 var clickPoints new List(float X, float Y) { (230f, 180f), (310f, 420f) }; // 两个点 var labels new Listlong { 1, 0 }; // 1前景0背景第二个点为负样本 // 计算归一化坐标图像已 resize 到 1024x1024直接除 var coords new float[clickPoints.Count * 2]; for (int i 0; i clickPoints.Count; i) { coords[i * 2 0] clickPoints[i].X / 1024f; // x 归一化 coords[i * 2 1] clickPoints[i].Y / 1024f; // y 归一化 } // 构造 Tensorshape: [1, num_points, 2] var pointCoordsTensor new DenseTensorfloat(coords, new int[] { 1, clickPoints.Count, 2 }); // labels Tensorshape: [1, num_points] var pointLabelsTensor new DenseTensorlong(labels.ToArray(), new int[] { 1, clickPoints.Count }); // orig_im_size原始图像尺寸用于 mask 反缩放 var origSizeTensor new DenseTensorlong(new long[] { 1920, 1080 }, new int[] { 2 }); // 原图 1920x1080关键细节point_coords必须是floatpoint_labels必须是longONNX 中int64用int会报InvalidArgument: Expected tensor of type Long but found Int32坐标归一化分母是1024模型输入尺寸不是原图尺寸orig_im_size传入的是原始图像宽高如1920,1080不是1024,1024否则输出 mask 尺寸错误。4.2 执行推理与解析输出避开 mask 尺寸陷阱ONNX 模型输出masks是[1, 1, 256, 256]的 float32 Tensor低分辨率 mask需上采样到原图尺寸// 构造输入字典 var inputs new ListNamedOnnxValue { NamedOnnxValue.CreateFromTensor(image, imageTensor), NamedOnnxValue.CreateFromTensor(point_coords, pointCoordsTensor), NamedOnnxValue.CreateFromTensor(point_labels, pointLabelsTensor), NamedOnnxValue.CreateFromTensor(orig_im_size, origSizeTensor), }; // 执行推理 using var outputs session.Run(inputs); var maskTensor outputs.First(o o.Name masks).AsTensorfloat(); // 输出 shape 是 [1,1,256,256]取第一个 mask var maskData maskTensor.ToArray().Skip(0).Take(256 * 256).ToArray(); // [256*256] // 上采样到原图尺寸双线性插值 using var lowResMask new Mat(256, 256, MatType.CV_32FC1, maskData); using var fullResMask new Mat(); Cv2.Resize(lowResMask, fullResMask, new Size(1920, 1080), 0, 0, InterpolationFlags.Linear); // 二值化阈值 0.0 Cv2.Threshold(fullResMask, fullResMask, 0.0, 255.0, ThresholdTypes.Binary);为什么输出是 256x256SAM 的 Mask Decoder 固定输出低分辨率 mask256x256再通过orig_im_size参数在后处理中上采样。若忽略orig_im_size直接Resize到1024x1024mask 会严重变形——这是新手最常踩的坑。4.3 一键抠图Alpha 合成与 PNG 导出最终输出需 PNG 带 Alpha 通道供下游使用// 读取原图BGR using var srcBgr Cv2.ImRead(input.jpg); // 转为 BGRA添加 Alpha 通道 using var bgra new Mat(); Cv2.CvtColor(srcBgr, bgra, ColorConversionCodes.BGR2BGRA); // 将 mask 转为 byte 并赋给 Alpha 通道 var alphaData new byte[1080 * 1920]; Marshal.Copy(fullResMask.Data, alphaData, 0, alphaData.Length); for (int i 0; i alphaData.Length; i) { bgra.Data[i * 4 3] alphaData[i]; // 设置 Alpha 值 } // 保存 PNG必须用 IMWRITE_PNG_COMPRESSION0否则 Alpha 通道压缩失真 Cv2.ImWrite(output.png, bgra, new[] { ImwriteFlags.PngCompression, 0 });提示ImwriteFlags.PngCompression0关键默认压缩等级 1 会导致半透明像素被强制二值化抠图边缘出现锯齿。实测设为 0 后 PNG 体积仅增 15%但边缘平滑度达标。5. 避坑指南C# ONNX SAM 生产环境 5 大血泪问题排查5.1 现象System.AccessViolationException在session.Run()时崩溃原因ONNX Runtime 的 Native DLL 与 .NET 运行时内存模型冲突常见于混合使用InferenceSession和Disposable对象如Mat未及时Dispose多线程并发调用同一sessionONNX Runtime Session 非线程安全DenseTensor构造时data数组被 GC 回收未 pin 住内存。解决每次推理创建独立session轻量初始化 50msDenseTensor必须用new float[]构造禁用stackallocMat对象务必using或显式Dispose()尤其在 WPF 的Image.Source绑定后。5.2 现象输出 mask 全黑或全白原因point_coords归一化错误或orig_im_size传入错误。排查打印point_coordsTensor 内容确认值在[0,1]区间用Cv2.ImShow(mask, fullResMask)直接显示上采样后 mask若为全 0 则point_coords无效检查orig_im_size是否传入1024,1024错误而非原图尺寸。5.3 现象CPU 推理耗时 3s远超预期原因未启用 AVX2 或线程数配置不当。解决在SessionOptions中设置sessionOptions.IntraOpNumThreads 4i5/i7 建议设为物理核心数确认 CPU 支持 AVX2用 CPU-Z 查看指令集旧 CPU如 i3-4170需降级到opset_version16并关闭GraphOptimizationLevel禁用 Windows 能量计划中的“节能模式”强制高性能。5.4 现象DirectML 初始化失败回退 CPU 后仍慢原因DirectML 需要 Windows 10 1809 且显卡驱动支持 DX12。排查运行dxdiag查看“显示”页的“功能级别”必须 ≥12_0更新显卡驱动至最新 WHQL 版本NVIDIA 515 / AMD Adrenalin 22.5.1若工控机用 Intel HD Graphics需 BIOS 中启用Intel VT-d和Above 4G Decoding。5.5 现象WPF 界面卡死鼠标点击无响应原因ONNX 推理阻塞 UI 线程。解决必须用Task.Run(() session.Run(...))异步执行WPF 中更新Image.Source时确保 BitmapSource 在 UI 线程创建await Task.Run(() { /* 推理 */ }); Dispatcher.Invoke(() { imageControl.Source CreateBitmapSourceFromMat(fullResMask); // UI 线程操作 });6. 进阶量化 ONNX 模型提速 40% 与跨平台部署验证6.1 量化 ONNX 模型INT8 代替 FP32SAM 的 ONNX 模型sam_vit_h.onnx约 2.1GBCPU 推理瓶颈常在内存带宽。量化到 INT8 可压缩至 1.2GB实测提速 35%i5-10400 从 820ms → 530ms# quantize.py from onnxruntime.quantization import QuantFormat, QuantType, quantize_static from onnxruntime.quantization.calibrate import CalibrationDataReader import numpy as np class SamCalibrationDataReader(CalibrationDataReader): def __init__(self, image_path): self.image cv2.imread(image_path) self.enum_data_dicts iter([{ image: preprocess_image(self.image), # 同前文预处理 point_coords: np.array([[[0.5, 0.5]]], dtypenp.float32), point_labels: np.array([[1]], dtypenp.int64), orig_im_size: np.array([1024, 1024], dtypenp.int64), }]) def get_next(self): return next(self.enum_data_dicts, None) # 执行量化 quantize_static( model_inputsam_vit_h.onnx, model_outputsam_vit_h_int8.onnx, calibration_data_readerSamCalibrationDataReader(calib.jpg), quant_formatQuantFormat.QOperator, per_channelTrue, reduce_rangeFalse, # False for AVX2 CPUs activation_typeQuantType.QInt8, weight_typeQuantType.QInt8, )C# 侧无需修改ONNX Runtime 自动识别 INT8 模型InferenceSession加载逻辑完全一致。唯一注意校准图片calib.jpg必须来自真实产线场景如金属零件图避免量化后泛化性下降。6.2 跨平台验证Linux ARM64 与 Windows x64 一致性测试为验证模型鲁棒性我在树莓派 4BARM64 Ubuntu 22.04和工控机x64 Win10上运行相同 C# 代码平台CPU推理耗时输出 mask PSNR备注Win10 x64 (i5-10400)6c/12t530ms42.1dBDirectML 加速Ubuntu 22.04 ARM64 (RPi4)4c/4t3200ms41.9dBCPU EP无 AVX关键发现ARM64 下Microsoft.ML.OnnxRuntime.Native需单独安装libonnxruntime1.16.3Ubuntu apt 源NuGet 包不包含 ARM64 native libPSNR 差异 0.3dB证明量化后数值一致性达标RPi4 上需关闭GraphOptimizationLevel设为ORT_DISABLE_ALL否则Gemm算子优化引发 segfault。6.3 我的生产级封装习惯抽象为SamSegmenter类为便于复用我将上述逻辑封装为可注入的 Servicepublic class SamSegmenter : IDisposable { private readonly InferenceSession _session; private readonly bool _useDirectML; public SamSegmenter(string modelPath, bool useDirectML true) { _useDirectML useDirectML; _session CreateSession(modelPath); } public async TaskMat SegmentAsync(Mat image, List(float X, float Y) points, Listlong labels) { // 预处理 → 推理 → 后处理 全部在此 return await Task.Run(() ExecuteSegmentation(image, points, labels)); } private InferenceSession CreateSession(string path) { var options new SessionOptions(); if (_useDirectML) options.AppendExecutionProvider_DirectML(0); else options.AppendExecutionProvider_CPU(); return new InferenceSession(path, options); } public void Dispose() _session?.Dispose(); }这样在 WPF ViewModel 中只需private async void OnImageClick(object sender, MouseButtonEventArgs e) { var point e.GetPosition(imageControl); var mask await _segmenter.SegmentAsync(_currentMat, new[] { (point.X, point.Y) }, new[] { 1L }); UpdatePreview(mask); }最后的经验不要迷信“一键抠图”的宣传词——真正的落地是把 ONNX 模型当做一个需要反复校准的工业传感器每次升级模型、更换相机、调整光照都得重新跑一遍精度验证。我现在的做法是在产线部署前用 500 张真实样本图生成mask_iou.csv要求平均 IoU ≥ 0.82低于则回滚模型。这比任何文档都管用。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号