前阵子帮一家工厂调试产线上的字符识别项目,需求本身不复杂:产品经过相机下方时,自动读取包装上的喷码批次号,跟数据库比对,不一致就剔除。听起来就是“拍照+识别”两件事,可真把这套视觉检测系统跑起来,才发现图像采集和 OCR 检测之间那些牵扯不清的细节,才是整个项目的真正难点。这篇文章我把这个项目的完整思路、硬件选型、采集流程、识别调优以及踩过的坑都整理出来,希望能帮到正在做类似项目的朋友。
1. 系统整体与核心思路拆解
1.1 先搞清楚需求,再谈方案设计
视觉检测系统的第一步,从来不是选相机、装软件,而是跟需求方把边界聊清楚。我自己接手项目的第一天,先问的是这几个问题:字符打在产品什么位置?是喷码还是激光打印?字符大小和排列是固定的还是经常换型?产线节拍要求多久出一次结果?
这些信息直接决定了系统的复杂程度。比如固定字符、固定位置,一张模板匹配就够用;但如果是多种产品混线生产,位置漂移又大,就必须上深度学习 OCR。很多项目做到一半推翻重来,就是因为需求调研时漏了“换型频率”这个关键参数——产品一换,原来的定位和识别规则全部失效。
我当时这个项目,产品是半哑光的深色塑料外壳,白色喷码,字符大小约 2 到 3 毫米,位置相对固定,但会有 1 到 2 毫米的左右偏移。节拍要求不高,每秒测一个就行。明确了这些条件,系统框架就出来了:工业相机负责图像采集,光源保证字符和背景有明显灰度差,先做图像预处理,再做定位和字符识别,最后比对规则输出 OK/NG 信号。
1.2 图像采集和 OCR 是强耦合的关系
很多人把图像采集和 OCR 当成两个独立模块,实际上它们之间的耦合关系非常紧密。图像采集决定了 OCR 能拿到什么样的输入数据,而这个输入数据的质量,直接决定了识别率的上限。
打个比方,这就像给身份证拍照:光线不对、角度歪了、手抖糊了,后面的身份核验自然过不了。OCR 引擎再强,也没办法在模糊到连人眼都分不清数字的图像上做准确判断。我在实际调试中反复验证过,很多识别率不稳的现场问题,根子都出在图像采集环节,而不是算法本身。
所以项目的核心思路不是“怎么跑通 OCR”,而是“怎么设计图像采集系统,让 OCR 能拿到一张足够干净、对比度足够高的图”。光源角度、相机曝光、镜头焦距、预处理参数,全部要围绕 OCR 的输入要求来调。
1.3 系统数据流与模块划分
整个系统的数据流是这样的:产品经过传感器,触发信号送给相机,相机抓拍图像并传回工控机,图像预处理模块先做灰度化、去噪、二值化,然后定位出字符区域,再裁切出 ROI 送给 OCR 引擎,识别出来的字符串与预设规则比对,最后把结果转成 IO 信号给到 PLC 或剔除机构。
我建议在做架构时把图像采集模块和识别模块解耦。图像采集只管出图,识别只负责文字解析,两边通过标准接口通信。这样调试时可以单独调光源和相机参数,不用动识别代码;后续想换识别引擎或增加新规则,也不会影响采集链路。项目上线后维护起来会轻松很多。
2. 硬件选型:相机、镜头与光源搭配实战
2.1 相机分辨率与帧率怎么定
相机选型第一个是分辨率。OCR 检测对像素精度有硬性要求。如果字符高度是 2 毫米,想稳定识别,字符宽度方向至少要保证 15 到 30 个像素。按最保守的 30 像素算,每个像素对应的物理尺寸不能大于 2/30 ≈ 0.067 毫米。
再根据视野宽度反推相机分辨率:比如视野是 100 毫米,那么相机横向分辨率至少要 100 / 0.067 ≈ 1500 像素。市面上 200 万像素的相机(约 1600×1200)勉强够,但我一般会往高里选,500 万像素更稳妥。分辨率高一点,后续 ROI 定位和倾斜校正的容差就大一点,不会因为一点偏移就切掉字符边。
帧率反而不用纠结。如果是静止抓拍,10fps 都绰绰有余;如果传送带运动不停,就需要缩短曝光时间来避免拖影,而不是单纯拉高帧率。我在项目里选的是 500 万像素、支持硬件触发、千兆网接口的工业相机,因为千兆网线可以做到 20 到 30 米稳定传输,适合现场布线。
2.2 镜头焦距与光圈调整细节
镜头选型的核心是算焦距。常规公式是 f = WD × S / FOV,其中 WD 是工作距离,S 是相机感光芯片的宽度,FOV 是视野宽度。
我项目里用的是 1/1.8 英寸芯片,感光宽度约 7.2 毫米。计划工作距离 200 毫米,视野宽度 100 毫米,算出来 f = 200 × 7.2 / 100 = 14.4 毫米,选 16 毫米定焦镜头最接近。如果视野要求变化,公式再重算一遍就行,不用凭感觉选。
光圈这里有个容易忽略的坑:为了追求亮度把光圈开到最大,会导致边缘画质下降和景深变浅。产品高度稍有波动,字符就虚了。我通常会把光圈收小一到两档,再适当加大光源亮度来补。另外,镜头上的对焦环和光圈环一定要用螺丝锁定,否则产线振动会让参数慢慢漂移,识别率会在不知不觉中下降。
2.3 光源方案:OCR 的光学设计是关键
光源是视觉检测系统里投入产出比最高的一环,也是最容易被新手轻视的一环。
喷码字符通常印在深色塑料外壳上,白色墨水。这种情况下,低角度环形光源或条形光源效果最好。光线以低角度斜射到字符表面,白色墨水的散射光和塑料外壳的直射光形成对比,字符边缘锐利清晰。而如果光源角度太高,光束垂直反射进镜头,很容易在塑料壳上形成一片亮斑,把字符完全吞掉。
对于铝箔、金属、玻璃这类强反光表面,普通光源很难处理,建议上同轴光源或加偏振片。同轴光通过半反半透的光路,让光线垂直于物体表面射入,可以有效减少杂散反光。
我在这个项目上做了一个简单实验:用两张不同角度的光源分别拍同一排字符,一组字符边缘有明显曝光,另一组干净利落。同样的 OCR 引擎,前者的识别率不到 90%,后者稳定在 99% 以上。同样的算法,差别全在光源上。
3. 图像采集流程与关键实现
3.1 触发与抓拍时机的控制
图像采集的触发方式一般有软件触发和硬件触发两种。产线上必须用硬件触发,不能靠程序里的定时器。
硬件触发的思路是:产品经过光电传感器时,传感器输出一个信号,信号经过 PLC 或直接进相机的 IO 接口,相机收到信号后立刻抓拍。这个过程中要确保一个关键点,就是产品刚好在视野正中央时触发。如果传感器安装位置靠前或靠后,拍出来的图像里字符位置就会偏移,后面做的 ROI 定位就会受影响。
我的做法是这样的:先把传感器固定在相机视野边缘的前方,产品通过传感器到进入视野中心有一个固定的时间延迟。在相机里设置一个触发延时,让产品到达画面中央的瞬间再曝光。延时的计算方式并不复杂,先测出传感器到视野中心的距离,再除以传送带速度,得到时间值。如果传送带速度不稳,就要用编码器来做位置触发,而不是单纯靠时间。
3.2 曝光、增益与白平衡的设置原则
采集参数里,曝光时间、增益和白平衡这三个是调试的重点。
曝光时间决定了运动拖影的严重程度。传送带速度越快,需要的曝光时间越短。但曝光时间短了,进光量就少,画面会偏暗。这时候有两个选择:加大光源功率,或者提高增益。增益会放大图像噪点,噪点多了以后二值化边界容易碎,OCR 误识别率会上升。我的原则是,光源能解决的事绝不用增益去补。所以实际操作顺序是:先把光源强度和环境遮光调好,再设定尽量短的曝光时间,然后看增益是否还有必要加。
白平衡对 OCR 项目影响不大,因为最终都会转成灰度图,但有一个细节要注意:如果原始图像是彩色图,白平衡不准会导致同一字符在不同区域的灰度值有偏差,影响二值化的稳定性。所以我在项目里直接把相机输出设为黑白模式,从源头避免色彩干扰。
还有一点很重要,所有参数调好之后,要把配置保存成模板。不然相机重启以后参数恢复默认,识别率一夜回到解放前。
3.3 图像预处理:灰度化、二值化与形态学操作
预处理是连接图像采集和 OCR 之间的桥梁。我一般用以下流程:
import cv2 import numpy as np # 读取灰度图像 img = cv2.imread("capture.bmp", cv2.IMREAD_GRAYSCALE) # 高斯滤波去噪,核大小根据噪点颗粒程度调整 blur = cv2.GaussianBlur(img, (3, 3), 0) # 自适应阈值二值化,避免固定阈值受环境光影响 binary = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 31, 15) # 开运算去掉孤立小噪点 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) # 提取连通域,定位字符区域 contours, _ = cv2.findContours(opened, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)这套流程里我最想提醒的是二值化。很多人会用固定阈值,比如 128 以下变黑、以上变白。看起来简单,但现场环境光稍微一变化,阈值就可能失效。自适应阈值会根据局部灰度分布自动调节,稳定性高很多。
开运算的作用是把图像里的孤立噪点去掉,但要注意核的大小。核太大,字符的细笔划也会被吃掉,结果字符连在一起,识别照样出错。核大小我一般从 3×3 开始调,最多用到 5×5。
字符区域定位这里,我习惯用外部轮廓而不是单个字符轮廓。因为喷码字符之间间距很小,二值化后很容易连成一片,直接提取单个字符容易切错,先定位整行再按列切割会更稳。
4. OCR 引擎选择与识别调优
4.1 模板匹配还是深度学习 OCR
很多人一听到 OCR 就想到深度学习,但在工业场景里,模板匹配反而经常是更优解。如果字符的字体、大小、位置都固定,用模板匹配速度快、占用资源小、调试简单,识别率能做到很高。模板匹配的原理是把标准字符图像做成模板,在 ROI 区域里滑动匹配,计算相似度。
我项目初期就用模板匹配,因为喷码的字体是设备固定的,批次号只有数字和大写字母,总共不过 30 多个模板,跑起来非常快。
但如果产品换型频繁,字体、字符大小、排列都可能变化,模板匹配的维护成本就很高了。这时候需要用基于深度学习的 OCR。深度学习 OCR 泛化能力强,可以应对变形、模糊、背景复杂的情况,但对样本数量、训练数据质量以及硬件性能都有要求。
所以我的建议是:按照需求来决定技术路线,不要为了用深度学习而用深度学习。先问一句:字符字体和位置是不是长期不变?如果是,模板匹配就是最稳最快的办法。
4.2 开源 OCR 引擎与易混淆字符处理
深度学习 OCR 方案中,选择开源 OCR 引擎是主流做法。通用 OCR 模型在印刷体识别上已经做得不错,但直接拿通用模型上线工业项目,还是会踩坑。
最大的坑是数字“0”和字母“O”,数字“1”和字母“I”之间的混淆。喷码字符本身就模糊,如果模型训练时没充分见过现场的字符样式,很容易判错。
解决办法有两个层面。第一,在业务逻辑层加规则校验。比如批次号第 1 位规定是字母,后面 6 位规定是数字,识别的结果不符合这个格式,就按 NG 处理。第二,在训练数据上下功夫。收集现场不同批次的图像,把“0/O”“1/I”这类混淆对单独标记,增加对抗样本,让模型学会区分。我的经验是,现场负样本比网上找的任何通用数据集都值钱。
4.3 自定义字符集与数据增强
如果公司有专门的 OCR 训练工具或用开源框架自己训练,一定先把自己项目的字符集确定下来。不要贪多,只把现场可能出现的字符加进去,字符集越大,模型越容易出现混淆。字符集确定后,要基于现场采集的图像做数据增强。
数据增强的常用手段包括:轻微旋转、平移、缩放、透视变换、亮度抖动、对比度抖动、添加噪声等。增强的目的是模拟产线上不同批次的差异。比如喷码机墨水浓度变化导致的字符粗细不均,模板匹配的算法就扛不住,但数据增强里加入随机形态学膨胀腐蚀后,深度学习模型就能学到这些变化。
我在这个项目上,先上线了模板匹配方案应急生产,同时让现场收集了约 2000 张真实图片,人工标注后做了数据增强扩充到 2 万张,再用深度学习模型替代了模板匹配。整个过程大约一周,识别率从 97.6% 提升到 99.5% 以上。
4.4 置信度阈值与结果后处理
OCR 引擎输出结果时通常带有一个置信度值,一般在 0 到 1 之间。千万不要直接拿识别字符串就做判断,置信度必须参与决策。
我的后处理逻辑是三层规则。第一层,置信度低于阈值(比如 0.7)直接判 NG。第二层,识别结果要做字符集校验,不允许出现字符集之外的字符。第三层,做格式校验,比如批次号必须匹配“字母+6 位数字”的固定格式。三层都通过才判 OK。
这样做的好处是,即使 OCR 引擎偶尔出错,规则层也能兜底,大幅压低误放行率。实际项目中我还把每张检测图像、识别文本、置信度、判定结果全部保存到本地数据库中,方便后续追溯。
5. 常见问题与排查实录
5.1 字符断裂与反光过曝
排障时遇到最多的问题是二值化后的字符笔划出现断裂,比如“8”被看成“3”。多数情况下并非 OCR 算法问题,而是图像本身就不干净。
排查思路是先回到原始图像,看字符边缘是否锐利。如果边缘有模糊、重影,检查曝光时间和光源强度;如果图像里有反光光斑,调整光源角度或加偏振片。预处理层面,针对断裂,可以加大开运算核的尺寸,让字符笔划连起来。但要控制好度,核太大容易把相邻字符也连在一起。
还有一个技巧是使用闭运算。闭运算能填充字符内部的细小空洞,对墨水不均匀造成的字符空心特别有效。
5.2 识别率白天高、晚上低
这个现象在工厂车间很常见,问题几乎都出在环境杂散光上。白天窗户漏进来的自然光、屋顶灯管、旁边设备的工作指示灯,都可能让图像亮度产生波动。自适应阈值虽然能扛一部分,但杂散光如果形成大范围渐变,还是会影响识别。
解决思路是物理隔离为主。我后来给相机视野区域做了一个遮光罩,把外部杂光挡在外面,识别率就稳定了。如果现场条件不允许遮光,可以在相机镜头前加带通滤光片,配合特定波长的光源工作,滤除环境光中的干扰成分。我带过一个项目就是用近红外光源加匹配滤光片,白天和夜里采集的图像几乎一模一样。
5.3 批量异常预警:把 OCR 当成质量监测工具
用久了你会发现,OCR 系统不仅能检测字符对错,还能反映喷码机本身的运行状态。字符平均置信度、笔划断裂频率、字符粗细变化,都是喷码机喷嘴堵塞、墨水浓度变化等问题的前兆。
我在系统里加了一个统计模块,按班次汇总误判率和置信度均值。置信度整体下降,说明喷码质量在变差,这时候去维护喷码机,能避免成批量的废品。这个方法等于把视觉检测系统从“事后剔除”升级成“事前预警”,对产线的帮助比单纯检测大得多。
5.4 一套配置换产品就失灵了
项目上线初期,经常出现这条产线产品换型号后识别率暴跌的情况。原因很简单:字符大小、对比度、位置都变了,而采集参数和识别参数还停留在旧型号上。
应对方法是建立“配方管理”机制。每个产品型号对应一套独立的参数配置,包括相机曝光、ROI 位置、二值化阈值、字符模板或模型权重。产品切换时,软件一次性加载对应配方。这套机制听起来简单,但能解决 80% 的产线换型问题。我的做法是把配方配置文件按产品编码命名,切换时靠 PLC 给一个型号信号,PLC 自动加载,效率和稳定性都高了。
就项目整体而言,最值得复盘的一点是:视觉检测系统里 90% 的坑都不在 OCR 算法本身,而是出在图像采集环节。光源角度差一点、曝光参数没锁好、环境光干扰没隔断,识别率都会明显波动。把这块基础打好,后面的识别调优才真正有意义。