纯C#无法原生实现图像识别,必须依赖ONNX Runtime、ML.NET或OpenCVSharp调用预训练模型;核心难点在于输入预处理(尺寸/归一化/通道顺序)和输出后处理(NMS/坐标映射)。

纯 C# 不装第三方库,做不了真正意义上的图像识别;所谓“C# 图像识别”,实际是调用封装好的模型推理接口,核心在 ONNX Runtime、ML.NET 或绑定 OpenCVSharp + Python 服务。直接写 Bitmap.GetPixel 遍历判色?那叫图像处理,不是识别。
用 ML.NET 做简单分类(如手写数字、logo 二分类)
ML.NET 适合轻量、.NET 原生集成、无需部署 Python 环境的场景,但只支持预训练管道或有限结构的自定义模型。
- 必须用
Microsoft.ML2.0+,旧版不支持图像输入;训练数据需转成ImageData类型(含ImageSource字符串路径 + 标签) - 不能直接喂
Bitmap对象,得先保存为文件(如temp.jpg),再传路径——否则报NotSupportedException: Image loading from stream is not supported - 模型导出后是
.zip,加载时用mlContext.Model.Load("model.zip", out var model),别误用.mlnet后缀(那是旧版文本描述) - 推理速度慢:单图约 300–800ms(CPU),不适用于实时视频流;若要提速,得手动把
ImageClassificationTrainer换成OnnxModelScorer加载 ONNX
用 ONNX Runtime 跑 YOLOv5 / ResNet(推荐主流做法)
这才是当前 C# 工程中真正可行的图像识别路径:Python 训练好模型 → 导出 ONNX → C# 用 Microsoft.ML.OnnxRuntime 加载推理。
- ONNX 模型输入尺寸必须严格匹配,例如 YOLOv5s 要求
[1, 3, 640, 640],传入Bitmap前得用Bitmap.Resize(640, 640)+ BGR 通道转换(OpenCVSharp.Cv2.CvtColor) - 别直接用
float[]喂数据:ONNX Runtime 要求float[, , ,]四维数组,且通道顺序为 NCHW(不是 NHWC),错一位结果全乱 - 常见错误:
InvalidArgument: Input 'images' has incompatible shape—— 多半是维度没 reshape 对,或图片没归一化到[0.f, 1.f](YOLO 系列通常要除以 255f) - 性能关键点:复用
InferenceSession实例,别每次 new;输入 tensor 用OrtAllocator.Default避免 GC 压力
OpenCVSharp + DNN 模块调用(免 Python,但模型少)
OpenCVSharp4 自带 DNN 模块,可直接读取 .onnx、.pb、.torchscript,适合快速验证,缺点是算子支持不如 ONNX Runtime 全。
- 必须显式设置后端和目标:如
net.SetPreferableBackend(OpenCvSharp.Dnn.Backend.OPENCV)+net.SetPreferableTarget(OpenCvSharp.Dnn.Target.CPU),否则默认用INFERENCE_ENGINE,会因缺 DLL 崩溃 - 标签文件(
classes.txt)每行一个类别,不能有空行;加载时用File.ReadAllLines("classes.txt"),别用Split('\n')——Windows 行尾是\r\n - 输出 blob 解析依赖模型结构:YOLOv5 输出是
[1, 25200, 85],需自己实现 NMS(非极大值抑制);SSD 输出是[1, 1, N, 7],第 7 维含置信度,可直接用Cv2.Dnn.NMSBoxes - 注意
Bitmap到Mat的转换开销:用Mat.FromImageData比先存文件再Cv2.ImRead快 5 倍以上
真正卡住人的往往不是代码怎么写,而是模型输入预处理和输出后处理——尺寸、归一化、通道顺序、NMS 阈值、坐标映射回原图,这四步错任何一环,结果就全偏。源码里最值得抄的不是主逻辑,是那几行 Resize → Normalize → Transpose → ToTensor 的 pipeline。










