工业视觉踩坑实录(十六):读个指针表,我差点以为计算机视觉是假的
读个指针表,我差点以为计算机视觉是假的
做视觉十年,我很少说"这活儿没法干"。指针表读数是我为数不多说出这句话的场景。
关于作者
我接触视觉整整10年。
工业视觉、烟草、煤矿等行业都有深度开发经验。从硬件选型、算法开发、模型训练,到上位机开发及部署,都在一线磨过。
之前是多家公司人工智能团队的技术负责人。现在自己创业了,还在继续做视觉落地这件事。
作者说
等等。
这篇跟前面的踩坑实录不太一样。前面那些都是做完项目之后的复盘——坑踩完了,教训也有了,坐下来写。这篇不是。
指针表读数这个活,我前后断断续续搞了一年多,换了四套方案,最后结论是——有些视觉问题,根子上就不是视觉能解决的。
这个结论不是我一开始就有的。是一步步踩出来的。
所以我决定用踩坑实录的方式写出来。不是教你怎么做指针表读数,而是带你走一遍我从自信到怀疑到认命的完整路径。看完你就知道,为什么我说做视觉十年,很少说"这活儿没法干",指针表读数是那为数不多的几次之一。
这是第十六篇。
开场先交代背景
指针式仪表,工厂里最常见的东西。电表、水表、油压表、气压表,本质都是一根指针在一个圆形刻度盘上转,指哪读哪。
听起来很简单对吧。
我一开始也这么想的。拿个目标检测模型把指针位置框出来,算一下指针和零点的夹角,角度乘以量程,完事。
实际跑下来,呵。
第一个坑:模板匹配在工作台上是神,在现场是垃圾
最开始用的方案是模板匹配。
先存一张指针在零位时的模板图,再存一张指针在满量程时的模板图,然后实时图进来,跟这两张模板做匹配,内插得到当前角度。
工作台上跑,准确率百分之九十九。我当时就觉得这活儿太简单了,甚至怀疑自己是不是把问题想复杂了。
到现场部署,第一天就崩了。
光线变了。同一个表,早上拍和中午拍,模板相似度能差出二十个百分点。为啥呢,因为表盘表面有轻微的油污或磨损,同一位置的光谱反射特性不是恒定的。模板匹配这东西,说到底是比像素值,光一变化,像素值就变,你还比个啥。
换方案。用Hough变换检测直线段,提取指针方向。这个方法对光照的鲁棒性好很多,工作台上测试效果也不错。
然后我发现了一个新问题:Hough变换找的是图像里最长的直线段,但指针不一定是图像里最长的线。表盘上的刻度线、装饰纹路、玻璃上的划痕,都可能贡献更长或更明显的直线段。Hough给你返回一个它认为的"最优直线",不一定是指针。
说到底,模板匹配和Hough变换,都是在假设指针是图像里最容易被识别出来的特征。但这个假设在工业现场根本不成立。指针细、对比度低、还经常被玻璃反光遮掉一截。你以为你在检测指针,其实你在检测一堆乱七八糟的东西里最像指针的那根。
后来换了思路,用YOLO-OBB。普通YOLO输出的是正矩形框,OBB(Oriented Bounding Box)输出的是旋转框,直接带一个角度值——框住指针,读出旋转角,完事。不需要Hough变换那一套直线检测再算夹角的流程,一步到位。
这个方法对传统方案的降维打击在于:它不假设指针是图像里最长的线,它只认你标注的指针长什么样。训练数据里你标注的是指针,模型学到的也是指针的特征。刻度线、装饰纹路、玻璃划痕,只要跟训练数据里的指针不一样,模型就不会把它们当成指针。
当然,代价也很明显。你需要标注数据,而且标注的是旋转框不是普通矩形框,标注成本高一些。但如果你的场景里指针种类不多(大多数现场就一两种表),几百张标注图就够训出一个效果不错的模型。
但旋转检测解决的是"指针在哪、朝哪个方向"的问题,它解决不了背景干扰的问题。反光、灰尘、水汽这些物理层的干扰,不管你用什么检测方法都会遇到。模型能学会指针的特征,但学不会"这坨高光是反光不是指针"这种判断——除非你把反光样本也加进训练数据里。这又回到了那个老问题:训练数据的覆盖度决定了模型的天花板。
后来我想明白了一个道理:不要去检测指针本身,去检测指针的缺失。什么意思,固定摄像头不动,先拍一张"没有指针"的表盘作为背景基准图。然后实时图进来,做差分。指针存在的区域,差分结果会显示出指针的轮廓;没有指针的区域,差分接近零。这个思路对光照的鲁棒性好很多,因为差分操作会抵消掉很大一部分全局光照变化。
想法很美好。但现实是——你上哪去弄一张"没有指针"的表盘图?
指针是表盘的物理组成部分,你不可能把指针拆下来拍一张纯表盘。停机检修的时候能不能拍?有些表可以把指针拨到零位拍一张当基准,但运行中的表你根本没这个机会。
后来我用了变通方案:多帧中值法。连续拍几十帧,指针在每帧里的位置不同,取所有帧的像素中值,指针会自然"消掉",留下的是纯表盘的背景。这个方法有效,但有严格的前提条件——摄像头必须绝对固定,光照必须稳定,而且需要拍够多帧才能保证中值效果。在振动大的车间或者光线频繁变化的环境下,中值法的效果也会打折扣。
还有一种路子是手动做:拍一张图,用图像编辑工具把指针区域涂掉,作为基准。每张表都要人工处理一次。算法上看起来干净,实际上把工作量从算法端搬到了人工端,成本一点没省。
所以差分法这个思路,理论上是对的,实践中能用,但永远不是开箱即用的。你得为它搭一套"基准图获取和维护"的流程,这个流程的复杂度有时候比算法本身还高。
第二个坑:角度算出来了,然后呢
好,指针位置检测问题基本解决了。你信心满满准备上线,然后发现下一个坑更隐蔽:你检测到了角度,但不知道这个角度对应的实际数值是多少。
你以为指针表都是均匀刻度吧,零点满度之间等分就是了。
不是的。
工业指针表有几种常见的非均匀刻度。第一种是对数刻度,常见于真空表或某些特殊气压表,刻度线在低压区域非常密,在高压区域非常稀。同样的角度变化,在低值区域对应的数值变化很小,在高值区域对应很大的数值变化。如果你的换算逻辑是线性的,读数会严重失真。
第二种是开方刻度,跟对数刻度正好相反,常见于某些流量表,刻度在低值区域稀,高值区域密。
第三种更恶心,我叫它红区表。某些压力表在超过某个阈值之后有一段红色区域,可能是危险区也可能是允许瞬时超载的区域。这段红色区域的刻度密度和白色区域往往不一样,有的甚至是非线性压缩的。你算出角度,映射到数值,还得判断当前读数落在哪个区间,不同区间用不同的映射关系。
所以,指针表读数的完整逻辑是这样的:指针角度→归一化位置(0到1)→判断所在区间→应用该区间的非线性映射→得到实际数值。少一步都会出错。
这个坑的恶心之处在于,它不是算法问题,是物理世界的欠约束问题。你没有办法从一张表盘图片里直接读出它的刻度映射关系,刻度分布本身包含的信息不够解出这个方程。你要么提前知道这张表的参数(通过查型号或手动标定),要么就得接受"读数仅供参考"这个结论。
第三个坑:双指针表盘,双倍快乐
有一种表盘上不是一根指针,是两根。
两根指针分别指向不同的参数,比如一个是当前值,一个是峰值记忆。有的峰值指针是手动复位的,有的是靠机械结构自己保持峰值。
双指针的检测方案比单指针复杂在哪,主要在区分和追踪。两根指针角度接近的时候,模型很容易把两根当成一根。如果用差分法,基准图的维护会更困难,因为其中一根指针的位置在实时变化,你不能简单地把"无指针"作为基准。
实际能用的区分手段有几种。
颜色区分。很多双指针表的两根指针颜色不同,一般一根红色一根黑色。这种情况下最简单,用颜色通道先把两根指针分离出来,分别计算角度就行。颜色差异就是你的天然标签。
时序区分。拍连续帧,观察哪根指针在动。动的那根是当前值指针,不动的那根是峰值记忆指针。拍个十来帧,谁动谁不动一目了然。这个方法不需要两根指针有任何外观差异,只要有时间维度的信息就够了。
但时序区分有一个明显的盲区:如果两个指针都不动呢?设备停机了,或者当前值恰好和峰值记忆值一样,两个指针指在同一个角度,谁也不动。这时候时序信息就失效了,你从连续帧里看不出任何区别,跟看一张静态图没有差别。
粗细形态区分。有些表的两根指针粗细不一样,一根细长一根宽短。用宽度特征或者形态学轮廓可以辅助区分。但这种方法鲁棒性一般,因为摄像头分辨率、拍摄距离的变化都会影响指针在图像中的像素宽度。
但有一个场景是真没办法的:两根指针颜色一样、粗细一样,又刚好重叠。你从一张静态图里根本分辨不出这里是一根还是两根,读出的角度也不知道属于哪个参数。
这种情况下我一般直接跟客户说:这个表换成数字表吧。不是我不愿意做,是物理条件不允许。你不能要求算法解决一个连人眼都分不清的问题。
第四个坑:玻璃后面的世界不是你想的那样
指针表前面有一层玻璃或有机玻璃。这层玻璃会带来三个问题。
反光。现场的光源,不管是日光灯还是LED,光线照到玻璃表面会产生镜面反射。如果光源角度刚好合适,反光区域比指针还亮。你的检测算法会认为反光区域是前景,指针反而变成了背景的一部分。没用。
水汽凝结。尤其在潮湿的车间环境,玻璃内侧有时候会有水汽凝结,形成局部模糊。指针在模糊区域就变成了一根灰灰的影子,边缘信息全部丢失。边缘检测算法直接失效。
灰尘静电吸附。工厂环境粉尘多,玻璃表面容易积累灰尘。静电吸附的粉尘颗粒会在图像上形成噪点,如果正好落在指针附近,会影响指针位置的精确定位。
玻璃反光的问题,最直接的办法是偏振片。在光源和摄像头前面各加一层偏振片,调整角度让镜面反射的光被过滤掉。这个方法的缺点是偏振片会损失一部分光强,在光照本身就不强的场景下会让图像质量进一步下降。
另一个思路是从斜上方打光。让光源和摄像头不在同一角度,指针和表盘的漫反射光线进入摄像头,而玻璃表面的镜面反射不会进入。这个方法更通用,但需要现场配合安装,不是所有场景都能实现。
至于水汽和灰尘,属于维护问题。我的建议是,在跟客户签合同之前,先确认现场的温湿度环境和表盘的清洁度能不能接受。如果不能接受,在报价里把定期人工清洁或者加防护罩的成本打进去。不要等到部署完了才发现这是个无底洞。
过渡到OCR:两个完全不同的世界
好,指针读数的问题基本理顺了。现在甲方说,表盘上的数字也要读。
你心想,OCR嘛,做了这么多年,轻车熟路。
进去之后发现,这是另一个世界。
指针检测是几何问题,OCR是模式识别问题。两个问题的求解思路完全不一样。指针检测你可以用Hough变换、差分法、模板匹配,这些方法都是基于图像的局部几何特征。OCR你要做的是把像素分布对应到字符类别,靠的是训练数据覆盖的字符样式。
指针表盘上的字符有几个特殊之处。
字符在曲面上。指针表盘不是平的,字符印在弧面上,会有畸变。越靠近边缘,畸变越严重。OCR模型如果是用平面上印刷的字符训练的,对这种曲面畸变的鲁棒性会很差。
字符类型非标准。工业表盘上的数字很多不是标准字体,有的手写感很强,有的加了很多装饰线,有的用凸版印刷的效果,字符边缘是模糊的。这些非标准字符对通用OCR模型的准确率影响很大。
字符非常小。指针表盘的有效面积有限,印在上面的数字可能只有二三十个像素高。通用OCR模型在低分辨率字符上的准确率会断崖式下降。
还有一个割裂的问题。指针检测和OCR是两套算法,各有各的输入条件。指针检测需要高对比度、精确的几何边缘;OCR需要清晰的字符笔画。这两个条件很难同时满足,同一套图像预处理参数,往往只能对其中一个优化。
OCR在表盘上的具体坑
小数点位置。有的表盘数字是"18",没有小数点,但实际数值是"1.8"。OCR识别出了"18",但小数点被指针挡住了,或者压根没印。这时候你的系统会输出18,而真实值是1.8,差了十倍。客户会追着你问为什么读数不对,你冤不冤。
单位字符。MPa、PSI、bar这些单位字符,有的表盘会印在刻度旁边,有的不会印。OCR识别出了数字,但不知道单位,还得靠人工配置或者额外检测。如果客户换了一个表,表盘上的单位变了,你的系统就会持续输出错误单位。
字符与背景的颜色搭配。工业表盘的颜色方案太多了。黑底白字、白底黑字、红底白字、绿底黄字,有的还带荧光效果。通用OCR模型的准确率在不同颜色搭配下差异很大。
我的经验是,对于指针表盘上的OCR,与其用通用OCR模型,不如针对这个场景单独训练或微调一个专用模型。表盘上出现的字符种类有限(主要是数字和少量单位),样式也相对固定,用少量数据微调一个模型,效果往往比通用模型好很多。
而且,微调模型的推理速度更快,资源消耗更低。对边缘部署场景来说,这一点很重要。
根因:指针表是一个欠约束的物理系统
写到这,我想停一下,说一个更宏观的认知。
指针表读数这个任务,看起来是计算机视觉问题,实际上是传感器融合问题。指针角度是一个物理量,表盘刻度是另一个物理量,两个量合在一起才能得到一个有意义的读数。你的算法能检测指针,但检测不了刻度分布的隐含规则。
从一张表盘图片里,你没法知道这张表的量程是多少、刻度是否均匀、是否有红区、是否是多指针系统。这些信息不在图像里,在物理世界里。你必须通过其他渠道获取这些先验知识,或者到现场做人工标定。
这也是为什么指针表读数系统没法做一个通用版本卖给所有客户。每张表都有自己的物理参数,系统必须针对每张表做适配。这个适配成本,就是这个生意的本质。
想明白这一点,你就知道该不该接这类项目了。如果客户能提供完整的表盘参数,方案可行;如果客户什么都不提供,就扔给你一张图让你读出数值,这个任务本身就是无解的。
工程问题的边界条件,往往比算法本身更重要。
总结
指针表读数的坑,按优先级排是这样的:
第一,任务定义要清楚。不是检测指针角度,是检测指针角度加上正确的物理量映射。两步缺一不可。
第二,现场条件比算法性能更关键。反光、灰尘、水汽、玻璃材质,这些物理层的问题不解决,再好的算法也是白搭。
第三,模板匹配和Hough变换都不是指针检测的银弹。根据你的实际场景选择合适的方法,差分法思路好但基准图获取是个难题,多帧中值法是变通手段但前提条件苛刻。
第四,从指针检测过渡到OCR,不是功能升级,是两个完全不同的技术栈。不要假设同一套预处理参数能同时服务两个任务。
第五,OCR在表盘上的核心挑战是字符样式非标准化和小数点位置确认。这两个问题不解决,数字读对了也没用。
第六,双指针表盘先看颜色区分,再看时序区分,实在分不开就跟客户建议换数字表。别硬上算法解决人眼都分不清的问题。
第七,也是最重要的一点:接手指针表读数项目之前,先确认你能拿到被读表盘的完整物理参数。如果客户说"你自己看图识别",转身就走,这个项目从根上就是错的。
这篇文章写的是指针表,但本质在说一件事:工业视觉的难点,从来不在视觉本身,在工业。
如果你也在做类似的事情,希望这份文章能帮你少接几个坑。
下一篇我会接着谈谈我之前的一个ocr项目。
📎 相关专栏
- 工业视觉踩坑实录
