OpenCV 二维码识别OpenCvSharp 相机取流 WinForms 显示萨达大 · 06-01 · 追溯读码是产线标配产线追溯、物料绑定、治具校验、出货标签复核——工位软件里「读二维码」出现频率极高。很多兄弟第一反应是 ZXing其实 OpenCvSharp 4 自带的QRCodeDetector已经能覆盖绝大多数 QR 场景检测定位点、透视校正、解码字符串一条龙。本文按上位机工程师的真实排期来写周一装 NuGet周二接 USB 相机周三把结果显示在 WinForms周四联调 PLC 上报。全文带可复制代码、现场调参口诀和 FAQ。一、为什么在上位机里用 OpenCV 读码工业 WinForms 项目往往已经引了 OpenCV 做测量或模板匹配再引一套读码库会增加部署体积和许可证心智负担。QRCodeDetector与Mat管线同源同一帧既可以读码又可以测边线程模型也统一。缺点也要说清楚码制支持以 QR 为主DataMatrix、PDF417 等仍需 ZXing 或商用读码器 SDK。若你的工位只有 QR 追溯OpenCV 足够且与下文圆形检测、模板匹配章节无缝衔接。二、工程准备与常见坑NuGet 引用版本号请与团队仓库锁定下面用 4.x 示意PackageReferenceIncludeOpenCvSharp4Version4.10.0.20240616/PackageReferenceIncludeOpenCvSharp4.runtime.winVersion4.10.0.20240616/平台目标务必 x64。OpenCvSharp 的 native 依赖在产线 PC 上几乎都是 64 位 WindowsAnyCPU 在部分机器会以 32 位进程运行然后你就看到经典的DllNotFoundException opencv_world。Release 模式下测一遍Debug 里帧率高不代表上线后 CPU 够用。首次集成建议在空 WinForms 里只放PictureBox 按钮「打开相机」「单帧解码」确认链路再并入主界面。萨达大见过太多「一上主窗体就卡死」——其实是 UI 线程里Read()阻塞了消息泵。三、QRCodeDetector 解码核心usingOpenCvSharp;usingOpenCvSharp.Extensions;publicsealedclassQrReaderService{privatereadonlyQRCodeDetector_detectornew();public(boolok,stringtext,Point2f[]corners)TryDecode(Matbgr){if(bgrnull||bgr.Empty())return(false,string.Empty,Array.EmptyPoint2f());usingvargraynewMat();Cv2.CvtColor(bgr,gray,ColorConversionCodes.BGR2GRAY);// 光斑不均可选 CLAHE注意只对 ROI 做以省时间// using var clahe Cv2.CreateCLAHE(2.0, new Size(8, 8));// clahe.Apply(gray, gray);stringtext_detector.DetectAndDecode(gray,outPoint2f[]points);boolok!string.IsNullOrWhiteSpace(text);return(ok,ok?text.Trim():string.Empty,points??Array.EmptyPoint2f());}}解码成功时points一般为四个角点可在图像上画绿色四边形操作员一眼可知「对准了没有」。若角点有了但text为空多半是对比度或模块损坏优先调光而不是狂加 GaussianBlur糊了更难解。多码场景OpenCV 提供 multi 接口OpenCvSharp 命名可能是DetectAndDecodeMulti一次帧内多个 QR 返回字符串数组。产线托盘多码时要配合 ROI 分区避免相邻码互相干扰。四、USB 相机 VideoCapture 连续取流publicsealedclassCameraGrabLoop:IDisposable{privateVideoCapture?_cap;privateThread?_thread;privatevolatilebool_run;publiceventActionMat?FrameReady;publicboolOpen(intdeviceIndex0,intwidth1280,intheight720){_capnewVideoCapture(deviceIndex,VideoCaptureAPIs.DMSHOW);if(!_cap.IsOpened())returnfalse;_cap.Set(VideoCaptureProperties.FrameWidth,width);_cap.Set(VideoCaptureProperties.FrameHeight,height);// 固定曝光若驱动支持不同相机属性 ID 可能无效需实测// _cap.Set(VideoCaptureProperties.AutoExposure, 0);returntrue;}publicvoidStart(){if(_capnull)return;_runtrue;_threadnewThread(CaptureLoop){IsBackgroundtrue,NameUvcGrabThread,PriorityThreadPriority.AboveNormal};_thread.Start();}privatevoidCaptureLoop(){usingvarframenewMat();while(_run_cap!null){if(!_cap.Read(frame)||frame.Empty()){Thread.Sleep(5);continue;}FrameReady?.Invoke(frame.Clone());}}publicvoidStop(){_runfalse;_thread?.Join(800);}publicvoidDispose(){Stop();_cap?.Release();_cap?.Dispose();_capnull;}}工业相机替代方案海康 MVS、Basler pylon 等 SDK 回调里拿到灰度或 BGR 缓冲区构造Mat后仍调用同一个QrReaderService。读码逻辑与相机品牌解耦这是上位机架构里该有的分层。五、WinForms 显示线程与去重界面刷新铁律后台采图 克隆 Mat BeginInvoke 更新 PictureBox。解码可与采图同线程也可丢进BlockingCollectionMat由专用解码线程消费避免读码耗时拖低帧率。privatereadonlyQrReaderService_qrnew();privatereadonlyCameraGrabLoop_camnew();privatestring_lastCodestring.Empty;privateDateTime_lastCodeTimeDateTime.MinValue;privatevoidBindCamera(){if(!_cam.Open(0)){MessageBox.Show(相机打开失败检查占用与驱动);return;}_cam.FrameReadyOnFrame;_cam.Start();}privateint_frameIndex;privatevoidOnFrame(Matmat){_frameIndex;booldecodeThisFrame(_frameIndex%20);// 隔帧解码降 CPUvarresultdecodeThisFrame?_qr.TryDecode(mat):(false,string.Empty,Array.EmptyPoint2f());if(result.okresult.corners.Length4){for(inti0;i4;i){vara(Point)result.corners[i];varb(Point)result.corners[(i1)%4];Cv2.Line(mat,a,b,newScalar(0,255,0),2);}}usingvarbmpBitmapConverter.ToBitmap(mat);varuiBmp(Bitmap)bmp.Clone();mat.Dispose();BeginInvoke(newAction(()UpdateUi(uiBmp,result.ok,result.text)));}privatevoidUpdateUi(Bitmapbmp,boolok,stringtext){pictureBox1.Image?.Dispose();pictureBox1.Imagebmp;lblStatus.Textok?$OK:{text}:等待二维码…;if(!ok)return;if(text_lastCode(DateTime.Now-_lastCodeTime).TotalSeconds2)return;// 去重防止连续触发 PLC/MES_lastCodetext;_lastCodeTimeDateTime.Now;OnQrAccepted(text);// 写日志、Modbus、数据库}privatevoidOnQrAccepted(stringcode){// 示例写 Info 日志见 07 章 NLog// Logger.Info(QR{Code}, code);}PictureBox 闪烁可开双缓冲更专业是用OpenCvSharp.UserInterface的PictureBoxIpl若版本提供或直接 GDI 画在 Panel 上。六、与 PLC / 追溯系统对接思路读码成功后的业务动作通常是校验格式正则、长度、前缀、查重同一盘料是否重复绑定、写寄存器或 HTTP 调 MES。视觉层只负责string code不要做 HTTP 在解码线程里同步阻塞用队列 后台 Worker失败可重试。萨达大建议码内容进日志时打掩码中间段***避免完整 SN 泄露到非追溯角色账号。七、现场调光与安装工作距离固定治具定位销比软件 ROI 更可靠。曝光读码工位尽量关自动曝光LED 补光用 diffuse避免 QR 表面镜面反射。分辨率模块边长至少占 20~30 像素更稳不够就升分辨率或光学放大。脏污用超时判定 NG并触发「请擦拭镜头」维护提示见 07 章 7x24 自愈。八、FAQQ1DetectAndDecode 一直空微信能扫说明光学/曝光问题居多。抓 RAW 帧保存 PNG看是否过曝一块白调整补光角度。软件侧试 CLAHE、仅 ROI 放大 2x 再解。Q2CPU 占用过高隔帧解码ROI 裁剪已知码在大致区域降低预览分辨率解码用全分辨率单帧 SDK 抓拍。Q3偶发误码QR 有纠错级别但工业仍应做格式校验必要时二次确认转治具再拍一次。Q4VideoCapture 打开 index 0 失败相机被其他软件占用尝试 index 1工业相机不要用 DSHOW换 SDK。Q5OpenCvSharp 与 EmguCV 混用不建议同进程混两套 native选一个栈统一。Q6需要生成 QR 吗OpenCV 也可生成打印标签一般用 Bartender/ZPL上位机只读。导航上一篇05-Excel/PDF 报表导出下一篇02-OpenCV圆形检测萨达大 · CSDN 上位机系列 · 欢迎收藏本目录索引九、ROI 与透视进阶当相机斜拍时QR 在图像里是梯形OpenCV 检测器内部会做透视变换但极端角度仍失败。机械上保证光轴近似垂直软件上可用四个角点GetPerspectiveTransform拉正后再 decode 备用通道。ROI 用Mat roi new Mat(gray, new Rect(x,y,w,h))裁剪注意 Rect 越界要 clamp。流水线节拍紧时先粗定位上一工位机械限位再小 ROI 解码单帧耗时可从几十毫秒降到个位数毫秒。publicMatSafeRoi(Matsrc,Rectr){r.XMath.Max(0,r.X);r.YMath.Max(0,r.Y);r.WidthMath.Min(r.Width,src.Width-r.X);r.HeightMath.Min(r.Height,src.Height-r.Y);returnnewMat(src,r);}十、错误处理与资源释放Mat必须using或显式DisposeFrameReady里克隆出来的 Mat 在 UI 线程画完要释放否则 GDI Bitmap 与 native Mat 双泄漏夜班跑八小时 OOM。相机线程退出前先Stop()再Dispose()FormClosing 里解绑事件避免窗体关了线程还在 Invoke。十一、测试清单上线前连续运行 2 小时无句柄泄漏任务管理器观察 GDI/句柄。强反光、弱光、偏一像素对焦各 100 次读码成功率达标。断拔 USB 相机软件不崩溃提示重连配合 07 章自愈。与 PLC 联调OK 脉冲宽度、NG 报警、重复码拒绝逻辑正确。日志可追溯时间戳、工位号、码内容脱敏策略评审通过。十二、延伸阅读本目录02讲圆与尺寸03把读码纳入 OK/NG 统计与 MES。07讲 NLog 与 7x24 异常处理读码线程的异常不要吞掉应进全局 Handler 并计数便于维护窗口看「今日解码失败次数」趋势。十三、OpenCvSharp 与 OpenCV 版本对应关系团队里若有人用 C OpenCV 做算法原型再交给 C# 集成务必对齐主版本号。minor 差异偶尔导致QRCodeDetector行为不同。升级 NuGet 前在测试工位跑 golden 样图集同一文件夹一百张历史 OK/NG 图统计解码率变化。萨达大习惯在仓库里放TestImages/Qr/作为回归资产CI 若条件允许可跑 headless 批量断言。十四、WinForms 设计器注意事项PictureBox.SizeMode建议Zoom避免拉伸导致操作员误判对准。状态栏显示「帧率 FPS」「解码耗时 ms」「相机名称」现场工程师会感谢你。快捷键 F5 单帧保存、F9 重新打开相机比鼠标点菜单快。多语言项目里错误提示用资源文件但日志保持中文或英文一种统一方便远程排查。十五、小结OpenCvSharp 的QRCodeDetector足以支撑典型 QR 追溯工位VideoCapture 或 SDK 供帧 → 灰度 → 检测解码 → WinForms 显示与去重 → 业务层写 PLC/MES。把线程和资源管理好再配合工程化章节的日志与自愈读码模块就能长期稳定跑在产线 PC 上。下一篇我们转向HoughCircles 与圆尺寸测量那是另一类视觉刚需。最后补一句部署习惯读码工位 PC 不要装杀软实时扫描相机 SDK 目录Windows 更新可设维护窗口避免周二上午整线停产等补丁。若你司信息安全政策必须扫描请把 OpenCvSharp native 目录加入白名单并记录在案。 现场若更换镜头焦距记得重新评估景深与读码距离并更新作业指导书上的示意图避免操作员按老经验摆料导致批量 NG。