高友谊

记录科研、技术与思考

给亲戚工厂做了一个流水线阀板视觉检测报警系统:从人工目检到自动拦截的一次小型产线改造

前段时间,帮亲戚工厂做了一个很接地气的小项目:流水线零件残缺/异常自动检测报警程序

说白了,需求并不复杂,但很典型:

  • 产线上零件需要持续过站;
  • 以前主要靠人工盯着看;
  • 一旦出现混料、划伤、锈斑、残缺或异常件,就希望系统能及时报警;
  • 最好还能顺手把结果统计下来,方便后面追溯。

一开始我并没有把它当成“多高大上”的 AI 项目去做,而是把它当成一个真正能在工厂现场跑起来的自动化工具:识别要稳、接线要简单、故障别轻易中断、出现 NG 之后要能直接给 PLC 发信号。

最后做出来的是一套轻量但完整的方案:模板分类防混料 + 缺陷检测 + PLC 报警输出 + 实时控制台面板 + 日志统计

一、这个项目到底要解决什么问题

工厂现场最怕的不是“识别率论文指标不够漂亮”,而是下面这些很现实的问题:

  1. 人工目检容易漏检
    工人长时间盯流水线,注意力会下降,轻微划伤、局部锈斑、错料件都可能漏过去。

  2. 不同型号零件容易混料
    只要上料或周转过程中出一点问题,就可能把 A 型和 B 型零件混在一起,后续装配会出更大问题。

  3. 现场节拍固定,系统必须跟得上
    不是离线跑图片,而是真正跟着产线节拍走,到了时间就得给出结果。

  4. 检测结果不能只停留在屏幕上
    产线真正需要的是:OK/NG 信号,必要时再带一个缺陷码,让 PLC 或执行机构去处理。

所以这个项目的目标一直很明确:

不是做一个“能识别图片的 demo”,而是做一个可以接近现场使用方式运行的、能自动拦截异常件的视觉检测程序。


二、为什么我没有一上来就上深度学习

很多人一看到“缺陷检测”,第一反应就是 YOLO、分割网络、训练数据集。

但这个项目的实际条件并不适合一开始就走重方案:

  • 样本量有限;
  • 项目周期短;
  • 现场更看重可落地、可解释、可快速调参
  • 缺陷类型相对明确,主要就是划伤、锈斑、混料/未知类型这一类问题;
  • 还需要兼顾 Windows / Linux、单相机 / 双相机、PLC 联动这些工程问题。

所以我最后选的是一套轻量规则 + 传统视觉方案:

  • 模板分类解决零件类型识别和混料拦截;
  • 颜色阈值 + 边缘/直线特征做锈斑和划伤检测;
  • Modbus-TCP 把检测结果写给 PLC;
  • 用脚本和配置文件解决生产启动问题。

这套方案最大的优点不是“最先进”,而是:

小工厂也能用,部署成本低,调试成本低,出了问题知道该改哪。


三、系统整体是怎么设计的

整个程序我拆成了几个非常实用的模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
valve_inspection/
├─ dataset/
│ ├─ templates/ # 模板库(良品图像)
│ └─ samples/
│ ├─ up/ # 上视图样本
│ └─ down/ # 下视图样本
├─ models/
│ └─ template_lib.pkl # 模板特征库
├─ results/ # 检测结果图、统计文件、日志
├─ run_demo.py # 主程序入口
├─ template_classifier.py # 模板分类 / 防混料
├─ defect_detector.py # 缺陷检测(锈斑 / 划伤)
├─ plc_io.py # PLC 通信
├─ camera_sim.py # 相机/文件读取模拟
├─ start_realtime.py # 跨平台启动器
├─ start_realtime.bat # Windows 启动脚本
├─ start_realtime.sh # Linux 启动脚本
└─ start_config.json # 启动配置

从职责上看,可以概括成一条链路:

图像采集 → 类型识别 → 缺陷检测 → OK/NG 判定 → PLC 输出 → 结果记录与统计

这条链路跑通以后,整个系统就不再只是“识别软件”,而更像一个轻量工业视觉工位


四、核心思路 1:先做模板分类,解决“混料拦截”

实际生产里,很多问题并不只是“表面有没有缺陷”,而是拿错料、上错料、混进去别的型号

所以我没有直接上来就做缺陷检测,而是先做了一个模板分类器

1. 模板库怎么建

每一种零件,先放几张标准良品图到 dataset/templates/ 里。
程序启动后可以先执行:

1
python run_demo.py --build

它会自动提取模板特征,并保存成 models/template_lib.pkl,后续运行时直接加载。

2. 分类器用了什么信息

这个分类器不是简单做一层像素比对,而是做了几种特征融合:

  • 形状主轴对齐:先做主方向归一化,减少角度变化影响;
  • Hu 矩:描述整体轮廓形状;
  • ORB 特征 + 匹配:提高局部特征鲁棒性;
  • HSV 直方图相似度:补充颜色/外观信息;
  • 拒识阈值:相似度太低时直接判为 type_UNKNOWN

这一步很关键,因为它把现场常见的“错料件”问题提前挡住了。

3. 为什么拒识比硬判更重要

在工厂里,“不确定”往往比“误判成正确”更安全

所以我给分类器设计了拒识逻辑:

  • 能够高置信度匹配模板 → 正常进入下一步;
  • 置信度太低或完全不像 → 直接判定为未知类型;
  • 如果开启混料拦截,就把这类件直接按 NG 处理。

这比“一定要猜一个最像的类别”实用得多。


五、核心思路 2:用规则法做缺陷检测

这个项目里的缺陷检测,主要针对两种比较典型的问题:

  • 锈斑
  • 划伤

因为零件材质、背景和拍摄环境相对可控,所以规则法其实很合适。

1. 先把零件区域分出来

为了避免背景干扰,我先做了一层钢件区域分割:

  • 把图像转到 HSV;
  • 利用绿色背景的颜色范围做反选;
  • 再做开闭运算,去掉噪点、补齐区域。

这样后面检测锈斑和划伤时,就尽量只在零件表面上做判断。

2. 锈斑怎么检测

锈斑在颜色上通常偏棕、偏橙、偏红褐,所以我直接在 HSV 空间里定义了一个棕橙色区间

  • 提取可疑锈斑区域;
  • 与钢件掩膜做与运算;
  • 做形态学开闭处理;
  • 计算面积;
  • 面积超过阈值就记为 rust

这种方法对现场快速落地非常友好,因为调阈值很直接。

3. 划伤怎么检测

划伤更像细长结构,所以我用的是:

  • 灰度化;
  • 高斯滤波;
  • Canny 边缘提取;
  • 霍夫直线检测;
  • 把较长线段合成为划伤掩膜;
  • 根据面积或覆盖范围做阈值判断。

如果最终区域超过阈值,就记为 scratch

4. 为什么这套方案在现场够用

它不依赖大规模标注数据,也不要求显卡环境,优点非常明显:

  • 可以快速上线;
  • 可以针对现场光照直接调;
  • 问题定位清晰;
  • 改规则的成本很低。

当然,它也不是万能的。对于形态特别复杂、缺陷类型很多、背景变化很大的场景,后续还是可以逐步升级到深度学习方案。


六、判定逻辑:什么情况下算 NG

系统最终不是输出一堆中间结果,而是要给出一个明确的工位结论。

我这里的判定逻辑比较直接:

判 NG 的情况

  • 检测到锈斑;
  • 检测到划伤;
  • 类型未知 / 拒识,且开启了混料拦截;
  • 现场读取图像失败或关键步骤异常(可按生产策略定义)。

判 OK 的情况

  • 类型识别正常;
  • 没有发现设定范围内的缺陷;
  • 结果可正常输出给 PLC。

也就是说:

先判断是不是正确的料,再判断这件料表面有没有问题。

这个顺序非常符合生产逻辑。


七、真正让它像“产线系统”的部分:PLC 联动

如果只是屏幕上显示 “OK / NG”,那它最多算半成品。

真正接近现场使用的是这一步:把检测结果通过 Modbus-TCP 写给 PLC

我在程序里封装了一个 plc_io.py 模块,大致约定了几类输出:

  • coil_ok = 0:OK 线圈;
  • coil_ng = 1:NG 线圈;
  • reg_code = 100:缺陷码寄存器。

缺陷码示例

缺陷类型 码值
scratch 5
rust 6
unknown 15

这样 PLC 收到信号后,就可以继续联动:

  • 报警灯;
  • 蜂鸣器;
  • 气缸剔除;
  • 传送带停机;
  • 后级分拣逻辑。

一个很实用的细节:自动模拟模式

现场开发时,不一定每次都有 PLC 真机可连。

所以我做了一个很实用的容错设计:

  • 如果 pymodbus 没装;
  • 或者 PLC 网络不通;
  • 或者连接失败;

程序不会直接崩掉,而是自动切换成模拟模式,只在控制台打印信号。

这对调试阶段非常友好,因为算法开发和设备联调可以并行推进,不会互相卡死。


八、支持单相机、双相机和单相机复用

为了适配不同工位预算,我没有把方案写死成某一种硬件模式,而是做了三种运行方式:

1. 单面检测

如果现场只看零件一面,可以直接:

1
python run_demo.py --live --up_only

这种模式对成本最友好,一台相机就够。

2. 双相机检测

如果正反面都要看,可以上、下各一只相机:

1
python run_demo.py --live --cam_up 0 --cam_down 1

3. 单相机复用

如果预算有限,但又想兼顾两面,可以通过节拍设计复用同一台相机:

1
python run_demo.py --live --single_cam

这种设计虽然简单,但对现场非常重要。因为很多时候,项目能不能落地,不只取决于算法,还取决于:

设备预算够不够,接线麻不麻烦,维护的人会不会用。


九、为了让工人也能看懂,我加了实时控制台面板

一个只会在后台悄悄运行的程序,对现场并不友好。

所以我在系统里做了一个实时控制台面板,用来显示:

  • 当前节拍;
  • PLC 状态;
  • 累计检测数量;
  • OK / NG 数量;
  • 良率;
  • 类型分布;
  • 最近一次的检测结果;
  • 最近一次 NG 的原因。

类似下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
========== 阀板视觉检测·实时面板 ==========
节拍:2.50 秒/件
PLC 状态:已连接
----------------------------------------------
累计:132 件 OK:126 NG:6 良率:95.45%
类型分布TOP3:type_A:120;type_B:10;type_UNKNOWN:2
----------------------------------------------
最近结果:
时间:2025-10-29 13:22:10
判定:NG
类型:type_UNKNOWN (score=0.07)
缺陷:scratch:1
提示/原因:混料拦截:类型未知/拒识;检测到缺陷:scratch
==============================================

这种面板的意义不在于“炫”,而在于:

  • 现场人员能快速知道系统有没有在正常跑;
  • 维修或调试时,可以马上定位是 PLC 问题还是识别问题;
  • 班组长也能直接看到良率变化。

十、统计和日志,决定了它是不是“可追溯”

如果检测完什么记录都不留,那后面复盘会非常麻烦。

所以系统运行时会自动生成几类结果:

  • session_stats.json:当前会话统计;
  • session_stats.csv:逐件结果明细;
  • live_records.jsonl:实时追加日志;
  • 检测结果图:把缺陷区域叠加到原图上。

这一步看起来不是算法核心,但实际很重要。因为一旦现场有人问:

  • 今天一共拦了多少 NG?
  • 哪一类缺陷最多?
  • 某个时间段是不是识别异常?
  • 这张图到底为什么判了 NG?

这些问题都得靠日志和结果图来回答。


十一、部署这件事,决定了项目能不能真正交出去

我在做这种小型现场项目时,一般不会搞特别重的部署体系,而是优先保证:

  • 别人拿过去能启动;
  • 工控机重启后能恢复;
  • 出错后知道去哪看日志。

所以这个项目里,我专门补了三种启动入口:

Windows

1
start_realtime.bat

适合直接放在工控机上双击运行。

Python 跨平台启动器

1
python start_realtime.py

它会读取 start_config.json,自动拼装参数,支持日志重定向和异常退出自动重启。

Linux

1
bash start_realtime.sh

适合边缘设备或者 Linux 工业主机部署。

我很喜欢这种“把工程入口做实”的方式。因为对工厂来说,真正重要的不是代码是不是优雅,而是:

今天开机以后,它能不能自己稳稳跑起来。


十二、这个项目里我比较满意的几个点

1. 不只做识别,还考虑了完整链路

从采图、识别、判定、PLC 输出,到统计和启动脚本,这条链路是闭环的。

2. 工程容错做得比较实用

比如 PLC 连不上自动走模拟模式,这就很适合现场开发。

3. 运行模式足够灵活

单相机、双相机、单面、双面都能兼容,后续改造空间更大。

4. 规则法虽然朴素,但真能快速落地

对于样本不多、现场目标明确的项目,这类方法的性价比很高。


十三、它目前的局限也很明显

这篇文章也不能只写优点,不然就成宣传稿了。

这个系统现在更适合:

  • 产品类型有限;
  • 背景相对稳定;
  • 缺陷类别较少;
  • 现场光照和工位位置比较可控。

如果后面继续迭代,我觉得至少还有几个方向可以升级:

1. 从规则检测升级到深度学习检测

当缺陷类型更多、更复杂、更细微时,传统规则会越来越难维护。

2. 做更完整的相机标定和光照控制

工业视觉很多时候不是“算法不行”,而是成像条件没控制好。

3. 增加样本管理和误判回流机制

把误判图片自动收集起来,后面无论继续调规则还是训练模型,都更方便。

4. 增加 Web 看板

把实时结果、历史统计、缺陷图像做成一个网页,比纯控制台更适合多人查看。

5. 和产线执行机构做更深联动

比如剔除动作确认、复位信号、异常连锁停机等。


十四、这次项目给我最大的感受

这个项目虽然不算“大”,但特别能体现一个事实:

真正的工业小项目,难点往往不在某一个算法,而在于你能不能把“识别、控制、容错、部署、使用体验”一起串起来。

很多时候,能在电脑里跑通并不算完成;
只有当它能在工厂工位上稳定运行,并且现场人员愿意用,它才真的有价值。

对我来说,这次更像是一次很完整的“小型产线自动化实践”:

  • 既有计算机视觉;
  • 也有工程接线和 PLC 通信;
  • 既要考虑识别逻辑;
  • 也要考虑操作员和维护人员怎么使用。

这种项目做下来,会比单纯刷一个模型 demo 更能锻炼人。


最后

如果只从技术关键词上看,这个项目其实不复杂:OpenCV、模板匹配/特征匹配、规则检测、Modbus-TCP、Python 脚本化部署

但如果从“真实可交付”来看,它已经具备了一个小型工业视觉系统该有的大部分骨架:

  • 能识别;
  • 能拦截;
  • 能报警;
  • 能统计;
  • 能启动;
  • 能排查问题。

后面如果我继续完善它,我大概率会沿着“更稳的成像条件 + 更强的缺陷识别模型 + 更完整的产线联动”这个方向走。

至少现阶段,它已经不是一个只会在本地文件夹里跑图片的 demo,而是一个真正朝现场应用迈出了一步的项目。