C# + AI 视觉检测:工业零件缺陷识别系统完整实现
工业产品外观缺陷检测是质量管控的核心环节,传统人工目检存在效率低、易疲劳、标准不一致等问题,而商用视觉软件(Halcon/VisionPro)授权成本高、定制化弱,Python推理方案又面临跨语言部署难、运维复杂、边缘适配差等痛点。
基于 C# + ONNX + ML.NET 的落地方案,可以直接将 AI 视觉能力嵌入现有 C# 上位机系统,全程在本地工控机完成采集、推理、控制全闭环,无需额外服务器、无需跨语言调用、无需专业视觉软件授权,是中小批量产线智能化改造的高性价比路径。
本文从系统架构、模型制备、核心推理、产线联动到工程化加固,完整拆解可直接落地的工业缺陷检测系统,所有逻辑均经过产线验证。
一、系统整体架构:边缘侧全闭环设计
工业视觉系统的核心原则是不影响生产、最小侵入现有产线,所有计算在本地工控机完成,断网也能正常运行,AI 故障可一键旁路。
1.1 四层解耦架构
1.2 核心设计原则
- 边缘优先:所有推理、控制全部在本地工控机完成,不依赖云端、不依赖内网服务器,断网不影响生产。
- 最小侵入:AI 模块以插件形式接入现有上位机,原有 PLC 控制逻辑不动,出问题可一键切回人工/纯机器视觉模式。
- 多级兜底:AI 检测异常时自动降级为传统阈值算法,再异常则旁路 AI,产线保持纯人工模式,绝对不能因为 AI 故障停线。
- 数据可溯:每个产品的原图、检测结果、缺陷位置、工艺参数、时间戳全部关联存档,支持按条码追溯。
二、算法选型与模型制备
工业场景的视觉模型,精度和速度重要,CPU 友好性、小样本泛化能力更重要——绝大多数工厂没有 GPU 工控机,也没有几万张标注样本。
2.1 模型选型:轻量优先,CPU 也能跑
工业缺陷检测首选 YOLO 系列轻量模型,平衡精度、速度、部署成本:
- 首选 YOLOv8n / YOLOv11n:参数量小、推理速度快,i5 工控机 CPU 单帧推理 30~80ms,完全满足产线节拍。
- 备选 MobileNet+SSD:算力极弱的嵌入式工控机可选用,速度更快,适合简单缺陷。
- 不建议用大模型:工业场景缺陷类别少、背景简单,大模型不仅跑不动,还容易过拟合。
2.2 训练侧:Python 训练 + 针对性优化
算法侧用 Python 完成训练,.NET 侧只负责推理,分工协作,兼顾算法丰富度与部署便捷性:
- 数据增强:工业缺陷样本少,必须做增强——旋转、翻转、亮度扰动、高斯噪声、随机遮挡,小样本下泛化性提升 30% 以上。
- 负样本训练:加入大量合格但有干扰(划痕、脏污、反光)的负样本,大幅降低现场误检率。
- 导出 ONNX:训练完成后导出 ONNX 格式,设置 opset=12,兼容所有版本 ONNX Runtime。
2.3 模型轻量化:INT8 量化必做
工控机无显卡的场景,INT8 量化是性能倍增器:
- 模型体积减少 75%,内存占用大幅降低
- CPU 推理速度提升 2~4 倍,640×640 输入可做到 50ms 以内
- 工业场景精度损失通常 <1%,完全可接受
- 工具:使用 ONNX Runtime Quantization 工具完成量化,推理侧无需改代码
三、核心实现:C# 端推理全流程
基于 OpenCvSharp 做图像处理,ML.NET + ONNX Runtime 做推理,全程 C# 实现,零 Python 依赖,可直接嵌入 WinForms/WPF 上位机。
3.1 图像预处理:工业场景的关键
工业现场光照波动、背景干扰多,预处理质量直接决定检测效果,不能直接把原图扔给模型。
publicclassImagePreprocessor{privatereadonlyint_inputSize=640;/// <summary>/// 工业图像预处理:ROI裁剪+光照归一化+缩放填充/// </summary>publicMatPreprocess(MatsourceImage,Rectangleroi){// 1. 裁剪ROI:只保留产品区域,排除背景干扰,同时减小推理尺寸usingvarroiMat=newMat(sourceImage,roi);// 2. 灰度化+CLAHE自适应直方图均衡:抵消光照波动、光源老化usingvargrayMat=newMat();Cv2.CvtColor(roiMat,grayMat,ColorConversionCodes.BGR2GRAY);varclahe=Cv2.CreateCLAHE(2.0,newSize(8,8));clahe.Apply(grayMat,grayMat);Cv2.CvtColor(grayMat,roiMat,ColorConversionCodes.GRAY2BGR);// 3. 等比例缩放+灰边填充,避免变形floatratio=Math.Min((float)_inputSize/roiMat.Width,(float)_inputSize/roiMat.Height);intnewW=(int)(roiMat.Width*ratio);intnewH=(int)(roiMat.Height*ratio);varresized=newMat();Cv2.Resize(roiMat,resized,newSize(newW,newH),0,0,InterpolationFlags.Linear);varpadded=newMat(_inputSize,_inputSize,MatType.CV_8UC3,Scalar.Gray);resized.CopyTo(newMat(padded,newRect((_inputSize-newW)/2,(_inputSize-newH)/2,newW,newH)));returnpadded;}}现场经验:ROI 裁剪是性价比最高的优化,既能减少背景误检,又能让实际推理区域变小,速度提升一倍以上。
3.2 推理引擎封装:ML.NET + ONNX
定义输入输出实体,构建 ONNX 推理管线,封装成可复用的检测服务。
publicclassYoloDetector:IDisposable{privatereadonlyMLContext_mlContext;privatereadonlyITransformer_model;privatereadonlyThreadLocal<PredictionEngine<ImageInput,DetOutput>>_enginePool;privatereadonlyint_inputSize=640;privatereadonlyfloat_confThreshold=0.5f;privatereadonlyfloat_iouThreshold=0.45f;privatereadonlystring[]_classNames;publicYoloDetector(stringonnxPath,string[]classNames){_mlContext=newMLContext();_classNames=classNames;// 构建ONNX推理管线varpipeline=_mlContext.Transforms.ResizeImages(outputColumnName:"images",imageWidth:_inputSize,imageHeight:_inputSize,inputColumnName:nameof(ImageInput.Image)).Append(_mlContext.Transforms.ExtractPixels("images",scaleImage:1f/255f)).Append(_mlContext.Transforms.ApplyOnnxModel(modelFile:onnxPath,outputColumnNames:new[]{"output0"},inputColumnNames:new[]{"images"},graphOptimizationLevel:GraphOptimizationLevel.ORT_ENABLE_ALL,intraOpNumThreads:4,interOpNumThreads:1));// 空数据拟合得到模型转换器varemptyData=_mlContext.Data.LoadFromEnumerable(new[]{newImageInput()});_model=pipeline.Fit(emptyData);// 工业固定线程场景用ThreadLocal,无锁竞争,延迟最稳定_enginePool=newThreadLocal<PredictionEngine<ImageInput,DetOutput>>(()=>_mlContext.Model.CreatePredictionEngine<ImageInput,DetOutput>(_model));}/// <summary>/// 执行检测,返回缺陷框列表/// </summary>publicList<DefectBox>Detect(MatpreprocessedImage,floatscaleRatio,Pointoffset){try{// 转换为MLImage输入varinput=newImageInput{Image=MLImage.CreateFromStream(preprocessedImage.ToMemoryStream())};// 推理varoutput=_enginePool.Value.Predict(input);// 解析输出 + NMS去重varboxes=ParseOutput(output.Output0,scaleRatio,offset);returnNmsSuppress(boxes,_iouThreshold);}catch(Exceptionex){LogHelper.Error("缺陷检测推理异常",ex);returnnewList<DefectBox>();}}}// 输入输出实体publicclassImageInput{[ImageType(640,640)]publicMLImageImage{get;set;}}publicclassDetOutput{[ColumnName("output0")]publicfloat[]Output0{get;set;}}publicclassDefectBox{publicfloatX{get;set;}publicfloatY{get;set;}publicfloatW{get;set;}publicfloatH{get;set;}publicfloatConfidence{get;set;}publicintClassId{get;set;}publicstringClassName{get;set;}}3.3 后处理:输出解析与 NMS
YOLO 原始输出是 84×8400 的张量,需要解析成检测框,并用非极大值抑制去除重复框。
privateList<DefectBox>ParseOutput(float[]output,floatscaleRatio,Pointoffset){varboxes=newList<DefectBox>();intnumClasses=_classNames.Length;intnumBoxes=output.Length/(4+numClasses);for(inti=0;i<numBoxes;i++){intoffsetIdx=i*(4+numClasses);// 置信度floatmaxConf=0;intclassId=-1;for(intc=0;c<numClasses;c++){floatconf=output[offsetIdx+4+c];if(conf>maxConf){maxConf=conf;classId=c;}}if(maxConf<_confThreshold)continue;// 坐标转换:中心点宽高 → 左上角宽高,映射回原图坐标floatcx=output[offsetIdx]/scaleRatio-offset.X;floatcy=output[offsetIdx+1]/scaleRatio-offset.Y;floatw=output[offsetIdx+2]/scaleRatio;floath=output[offsetIdx+3]/scaleRatio;boxes.Add(newDefectBox{X=cx-w/2,Y=cy-h/2,W=w,H=h,Confidence=maxConf,ClassId=classId,ClassName=_classNames[classId]});}returnboxes;}/// <summary>/// 非极大值抑制:去除重叠重复框/// </summary>privateList<DefectBox>NmsSuppress(List<DefectBox>boxes,floatiouThreshold){varresult=newList<DefectBox>();varsorted=boxes.OrderByDescending(b=>b.Confidence).ToList();while(sorted.Count>0){varcurrent=sorted[0];result.Add(current);sorted.RemoveAt(0);for(inti=sorted.Count-1;i>=0;i--){if(CalculateIoU(current,sorted[i])>iouThreshold)sorted.RemoveAt(i);}}returnresult;}四、工业场景专项优化:从 Demo 到量产的关键
实验室跑通 Demo 只完成了 30%,剩下 70% 都在解决现场的光照、干扰、误检问题。
4.1 ROI 掩膜机制:屏蔽固定干扰
产品上的螺丝孔、倒角、印刷字符等固定结构,很容易被模型误判为缺陷。提前制作掩膜图,落在掩膜内的检测框自动过滤,误检率可降低 50% 以上。
- 支持多边形、矩形、圆形多种掩膜形状
- 不同产品对应不同掩膜模板,换型自动加载
- 掩膜可在界面上可视化编辑,现场工程师即可调整
4.2 光照自适应:抵消光源老化
工业 LED 光源会随使用时间亮度衰减,半年后亮度可能下降 30%,直接导致检测阈值漂移。
- 每次检测先计算 ROI 区域平均灰度,偏离基准值时自动做亮度补偿
- 配合 CLAHE 直方图均衡,弱化光照不均的影响
- 设置亮度上下限,超出范围触发光源告警,提醒运维更换光源
4.3 缺陷分级与规则二次校验
AI 输出原始结果后,还要经过业务规则二次校验,进一步降低误检:
- 面积过滤:缺陷面积小于最小可接受值的直接忽略,避免噪点误判
- 区域分级:关键区域(密封面、配合面)缺陷从严,非关键区域放宽标准
- 数量限制:单产品缺陷数量超过阈值直接判定不合格
- 类型匹配:某些缺陷只允许出现在特定区域,出现则直接升级严重等级
4.4 多产品模板化管理
一条产线通常生产多种型号零件,所有参数模板化管理:
- 每个产品对应独立的 ROI、掩膜、检测阈值、模型文件
- 扫码获取产品型号,自动加载对应模板
- 换型无需重启程序,秒级切换
五、产线联动:从检测到执行的闭环
视觉检测不是孤立的图像处理,必须和产线时序、PLC 控制深度结合,才能真正落地。
5.1 硬触发时序:保证拍照位置一致
绝对不要用软件触发拍照,必须走硬件触发,保证每次拍照时工件位置完全一致:
- 工件流到检测工位,光电传感器触发
- PLC 输出触发信号给相机,同时给上位机帧信号
- 相机硬触发曝光拍照,上传图像给上位机
- 上位机检测完成,将结果写入 PLC 寄存器
- 工件流到剔除工位时,PLC 根据结果决定是否剔除
5.2 状态机管控:全流程可控
用状态机管理检测流程,避免时序混乱,出问题也容易排查。
publicenumDetectState{Idle,// 待机WaitTrigger,// 等待触发信号WaitImage,// 等待相机图像Detecting,// 检测中OutputResult,// 输出结果到PLCWaitPlcAck,// 等待PLC执行应答Error// 异常状态}每个状态有明确的进入条件、超时时间、异常处理路径,不会出现逻辑死锁。
5.3 剔除精准控制:传送带跟随
连续运动的传送带,不能检测完立刻发剔除信号,要计算延迟:
- 根据传送带速度和检测工位到剔除工位的距离,计算固定延迟时间
- 配合编码器脉冲计数,精准对应到工件位置,避免剔错
- 增加剔除确认传感器,验证剔除动作是否执行,防止漏剔
5.4 数据溯源与质量统计
- 每个产品的原图、缺陷标注图、检测结果、工艺参数、时间戳、条码号绑定存入本地 SQLite
- 支持按时间、批次、条码、缺陷类型查询回溯
- 自动生成日/周/月质量报表,缺陷类型占比、不良率趋势、工位分布
- 可对接 MES 系统,自动上传质量数据
六、工程化加固:7×24 小时稳定运行
6.1 模型热更新:不停产迭代
工业产线不能随便停机,模型更新必须做到无感知:
- 后台线程异步加载新模型,运行基准样本校验
- 校验通过后,使用读写锁原子切换全局推理实例
- 旧实例延迟 60 秒释放,等待存量检测任务完成
- 保留最近 3 个稳定版本,随时可一键回滚
6.2 多级降级兜底
AI 永远是辅助手段,不能成为单点故障:
- 正常模式:AI 全功能检测
- 轻降级:AI 置信度不足时,补充传统 blob 分析二次校验
- 重降级:AI 连续异常,自动切换为传统灰度阈值检测,保证基础检测能力
- 旁路模式:全部异常,关闭 AI 检测,产线切人工目检,界面告警
6.3 性能与内存优化
- 图像对象池:Mat 对象池化复用,避免频繁创建销毁,减少 GC 卡顿
- CPU 亲和绑定:推理线程绑定到指定 CPU 核心,不抢占控制线程资源
- 线程优先级:控制线程 > 采集线程 > 推理线程,保证生产控制优先级最高
- 低峰期 GC:换班、停机时段主动执行完整 GC + LOH 压缩,避免长时间运行内存上涨
6.4 异常自愈机制
- 相机掉线:自动尝试重连相机,连续失败触发声光告警
- 推理异常:单帧异常直接跳过,不影响下一帧;连续异常自动重启推理引擎
- 程序崩溃:配套独立守护进程,主程序异常退出自动重启,恢复到运行状态
七、现场高频踩坑与避坑指南
坑1:光照波动导致误检率飙升
- 现象:上午测的好好的,下午就误检变多;新光源很准,用三个月就不准了
- 解决:加入光照归一化预处理,设置亮度基准范围,超出自动补偿;定期校准光源;不要用绝对亮度阈值,用相对对比度判断缺陷。
坑2:反光、油污干扰,误检多
- 现象:金属表面反光、油污痕迹,经常被当成划痕、压伤
- 解决:光源选型用漫射光源、偏振光源,从硬件减少反光;软件侧加掩膜和面积过滤,结合缺陷形状特征二次区分;训练时加入大量反光、油污负样本。
坑3:工件运动拖影,检测不准
- 现象:连续运动的产线,拍出来的图有拖影,缺陷定位不准、漏检
- 解决:硬件上加频闪光源,短时间高亮曝光冻结运动;软件上提高快门速度;实在不行就加工位停稳再拍。
坑4:缺陷样本太少,模型泛化差
- 现象:几十张缺陷样本训出来的模型,现场一用就漏检误检
- 解决:小样本场景优先做数据增强,翻转变换、亮度扰动、合成缺陷;用预训练模型微调,不要从零训;初期配合规则兜底,边跑边积累样本,逐步迭代模型。
坑5:工控机性能不足,节拍跟不上
- 现象:检测速度慢,工件流走了还没出结果
- 解决:做 ROI 裁剪,缩小推理尺寸;用 INT8 量化模型;优化后处理逻辑;实在不够就加推理线程分批处理,优先保证产线节拍。
八、落地价值总结
基于 C# 的工业 AI 视觉方案,相比传统方案有明确的落地优势:
- 成本低:不需要商业视觉软件授权,不需要额外算法工作站,复用现有工控机和上位机技术栈。
- 落地快:直接嵌入现有上位机系统,不用改产线架构,单工位 1~2 周即可完成部署调试。
- 易维护:全栈 C# 技术体系,工控团队就能自主维护,不需要专职算法工程师驻场。
- 安全可控:所有数据本地处理,不出厂区,满足工业数据安全与合规要求。
对于制造业工厂而言,AI 视觉检测不是高大上的演示项目,而是要真正解决质量管控的实际问题。用 C# + ML.NET 的轻量化方案,从单一工位切入,小步快跑、持续迭代,是绝大多数中小制造企业都能走通的智能化路径。
