OpenCV 生产落地案例:端侧缺陷检测与 Python 到 C++ 的迁移
生产落地案例:端侧缺陷检测与 Python 到 C++ 的迁移
案例一:ARM 板上的表面缺陷检测。背景是一条产线的表面质检工位,需要在设备端实时判断产品表面是否存在划痕,网络条件不允许上传云端。硬件是一块 ARM64 Linux 板加工业相机。
做法是用 videoio 抓帧,用 imgproc 做灰度、去噪与自适应阈值得到候选区域,再把疑似区域送进 dnn 加载的 ONNX 分类模型做二次确认,最后用 NMSBoxes 合并重叠框并输出结果。BUILD_LIST 只保留 core,imgproc,imgcodecs,dnn,关掉 highgui、OpenCL 与 TBB,静态链接后随应用一起打包。
关键配置集中在三处:一是 blobFromImage 的 size、scalefactor、mean、swapRB 必须与训练时完全一致;二是 setPreferableBackend 与 setPreferableTarget 明确设为 CPU 目标,避免在不支持的后端上反复回退;三是阈值与 NMS 的 score_threshold、nms_threshold 先用 Python 脚本在同一批图上扫一遍再固化。
效果是产线不再依赖网络,单机即可完成判定,同时因为模块裁剪,库体积与启动时间都比全量构建小得多(具体数值取决于工具链与选项,以实际测量为准)。踩的坑有三个:一是最初忘了通道序,Python 原型里用的是 blobFromImage(..., swapRB=True),C++ 版本里已经先 cvtColor 成 RGB 却又把 swapRB 设成了 true,等于交换了两次,缺陷漏检率异常升高,统一预处理入口后解决;二是 NMS 的输入框是归一化坐标还是像素坐标没对齐,导致框位置整体偏移,后来把后处理里坐标还原这一步单独写成函数并加断言;三是早期开了 OpenCL,在集显上首次初始化开销明显,关掉后启动更稳定。
案例二:Python 原型迁移到 C++ 时的精度对齐。背景是团队用 Python 调好了检测流程,迁到 C++ 上板时发现结果与 Python 不一致。
做法是逐环节做等价性验证:先用同一张图对比 imread 的结果是否逐像素一致(比较 Mat 的哈希或均值方差),再对比 resize 的插值方式是否都用了 INTER_LINEAR,然后对比 blobFromImage 的六个参数是否一一对应,最后对比后处理的坐标还原与阈值。多数不一致都能在这四步里定位。
效果是迁移周期从反复试错变成按清单核对。踩的坑集中在两个地方:一是 Python 里的切片与 OpenCV 的 ROI 语义不同,Python 版对图像做了 letterbox 补边而 C++ 版是直接拉伸,输入分布变了导致阈值失效,统一成同一个 letterbox 实现后对齐;二是 Python 中 numpy 的默认类型与 C++ 的 float32 转换时机不同,归一化用整数除法把小数截断了,改成先转浮点再除以 255 后解决。这类问题的通用经验是:把预处理与后处理写成两端各自唯一的一份实现,并用同一张测试图做逐环节比对,不要凭感觉排查。

