如果只看送检样件,TVA这套方案在实验室里的表现几乎是满分:误检率低得让人想直接签验收单。但把它搬上3C产品视觉检测的量产线之后,我才真正体会到什么叫“破局”和“重构”——不是算法又准了几个点,而是整个检测链路被现场问题反复锤打后,重新长出了不一样的结构。TVA的全称我们内部定义为Three-layer Vision Architecture,也就是三层视觉架构,专门用来处理3C外观检测里那些“看着不难、一上线就崩”的缺陷。这篇是系列第三篇,前面聊过成像方案选型和模型方向,这篇我重点讲落地:为什么必须分层、分层之后现场数据长什么样,以及两个让我印象极深的排查案例。
1. 为什么3C外观检测总在“漏检”和“过杀”之间摆钟
1.1 产线换型太快,方案跟着“调参”是死路
3C产品线的特点就是“快”和“杂”。今天这条线跑的是A客户高光黑色后盖,明天可能就换成B客户磨砂金属中框,再过几天又来个透明件的摄像头支架。每换一种材质、每改一次表面工艺,图像特征都会变一遍。
我们最早的做法和大多数团队一样:方案不够,调参来凑。换型之后,算法工程师的第一件事就是去产线重新采图,调整阈值、切换光源、补建模板。这套流程走下来,半天到一天就没了,而且每次调完都提心吊胆——因为你不确定这次调整会不会让另一种缺陷漏掉。
表面上看是“工作量问题”,实际上是“架构问题”。单模型方案把所有判断压力都压在一个分类器上,而这个分类器对光照、材质、纹理方向极其敏感。只要一个条件变了,它的决策边界就失效。与其说是我们不够努力,不如说是在用一个脆弱结构硬扛多变场景。
1.2 传统单模型的三个天花板:对比度、样本量、语境缺失
我后来把传统方案的局限总结成三个天花板,几乎每个3C项目都会踩到。
第一个是对比度天花板。很多缺陷先天就和背景长得太像:拉丝面上的浅划伤,人眼要拿手电倾斜45度才看得出来;透明件里面的气泡,常规照明下就是一团模糊影子。模型再强,也拿一张缺陷跟背景几乎融为一体的图像没办法。这就是“成像没做好,算法来背锅”。
第二个是样本量天花板。3C缺陷样本收集本来就难,良品几万张,缺陷可能只有几十张,某些稀有缺陷可能几个月才出现一次。单模型要同时学会所有缺陷形态,数据根本喂不饱。更头疼的是,一旦出现一个新缺陷类型,你得重新攒样本、重新标注、重新训练,中间这段空窗期全靠肉眼盯。
第三个是语境缺失天花板。同样是划伤,出现在可视面上可能是致命缺陷,出现在装配面上可能根本没人关心。单模型只能输出“OK”或“NG”,它不知道产品标准是什么,不知道这个缺陷在哪个区域、什么方向、多大尺寸才算超标。这类知识没办法写到像素分类里,只能靠外部规则补。
1.3 最后一根稻草:一个漏检事件让我们决定推倒重来
真正让我们下决心重构的,是一个不算特别严重的漏检事件。当时现场反馈过杀率偏高,我们为了让产线稳住,把分类阈值往上抬了一点。结果当天就有一批“深色小花纹”漏掉了——那种花纹在正常光线下几乎看不见,质检员用手电筒逐件抽查才发现,那批外观件返工了两次。
复盘的时候,大家其实都清楚问题出在哪:阈值一旦上调,处于灰色地带的缺陷就会从“轻微可疑”变成“直接放过”。单模型方案本质上是一个黑盒,你无法让它在某个局部变得更严格,又不影响其他地方。我们当场决定停止“补丁式”调参,开始按三层架构重构检测链路。
2. TVA破局的三次关键取舍:不堆模型,改成切分层
2.1 第一层取舍:先把“让缺陷显形”变成硬约束
TVA的第一层不是模型,而是成像。我们内部有一条很轴的规矩:缺陷在图像里看不见,算法再好也白搭。
以前布光是“能看清产品就行”,现在布光是“让缺陷和背景的对比度最大化”。划伤类缺陷要用低角度条形光,让表面微起伏产生高亮或暗影,形成一条明确的引导线;镜面外观要用同轴光或穹顶光源,避免硬反光把整个视野打白;拉丝金属表面则用两个方向的光交替照明,分别采集顺纹和逆纹的图像信息。
这一步听起来简单,但实际推进时会发现,光学工程师和算法工程师经常互相“甩锅”。所以我们在架构上明确:成像质量是检测效果的第一责任人,谁布的光、谁拍的图,谁就必须对后续误检负责。很多缺陷之所以难检,不是算法不行,而是光源角度一偏,对比度就没了。
2.2 第二层取舍:粗检只做召回,不做精确分类
TVA的第二层是粗检。这一层的目的非常纯粹:从大图上找出所有“不对劲”的候选区域,至于它到底是什么缺陷,先不管。
我经常用安检闸机来打比方:粗检就像闸机口的保安,宁可多拦几个看起来可疑的人,也绝不能让真有问题的人混过去。哪怕每张图拦下来一两百个候选框都没关系,只要那个真正的缺陷一定在里面就行。
实现方式可以很灵活。可以做背景差分,可以做局部梯度异常检测,也可以用轻量级分割模型。核心指标只有一个:召回率。粗检阶段一旦开始纠结精确率,就会不由自主地收紧阈值,那就又回到单模型的老路上了。
这层取舍最大的好处是让算法团队松了口气。以前的模型既要“找得到”又要“判得准”,两件事互相打架;现在把“找”和“判”拆开,每一层都能用最简单、最稳定的方式做自己最擅长的事。
2.3 第三层取舍:把“产品知识”写回判定逻辑
TVA的第三层是细分类加语义校验。候选ROI被裁出来之后,先送进细分类模型,判断它属于划伤、脏污、凹坑、毛刺、异物等哪一类,然后进入判定引擎。
关键就在判定引擎这里。最终放行或拦截,不是细分类模型单独说了算,而是把分类结果、几何尺寸、位置、方向、缺陷数量、产品标准放在一起综合计算。举个例子:同样是划伤,出现在可视面且长度超过1毫米,判NG;出现在装配面,长度低于3毫米,可以放行。脏污如果可擦除,先进入复判流程,而不是直接判死。毛刺方向如果和开模方向一致,脱落风险更高,判定权重就更大。
这类“产品知识”以前散在工艺人员脑子里,现在被结构化地写进判定规则。这是TVA和传统方案最大的分水岭:模型负责“看见”,规则负责“理解”。两者打通之后,过杀率才能降下来,因为很多以前被判NG的样本,本质上只是“模型不认识这个语境”,而不是“产品真的有问题”。
3. TVA重构后的完整检测链路:从成像到判定怎么串起来
3.1 一条完整的检测样本流长什么样
重构之后,我们的检测链路大概是这样的:
- 上料定位,触发相机拍照。
- 工位一:45度环形光成像,负责整体脏污、大颗粒异物。
- 工位二:低角度条形光成像,光方向与拉丝纹理垂直,负责划伤、浅凹坑。
- 工位三:同轴光成像,负责镜面外观的微小压伤和指纹类脏污。
- 各工位分别做粗检,产出候选区域。
- 候选区域按位置坐标合并成ROI列表,剔除跨工位重复项。
- 每个ROI被裁切后送细分类模型,打上缺陷类型标签。
- 判定引擎结合产品规则输出:放行、拦截、复检。
- 被拦截的工件进入人工复判通道,所有标签回流样本库。
需要特别强调的是,多工位的图像不是简单拼成一张“大图”再喂给模型。同一个缺陷在不同光照下长得很不一样,直接合并反而会干扰模型。我们的做法是每个工位独立粗检,最后只汇总候选坐标和对应图像块,保留光照信息进入下游。
3.2 关键参数与工位设计怎么定
很多团队问我们的参数是怎么定的,这里给一组比较典型的初始值作参考:
| 参数项 | 典型配置 | 说明 |
|---|---|---|
| 相机分辨率 | 500万~1200万像素 | 按视野大小与最小缺陷尺寸反推 |
| 最小缺陷尺寸 | 0.1mm | 要求缺陷在图像上至少覆盖3×3像素 |
| 工位一照明 | 45度环形光 | 主要覆盖脏污、异物、大面积色差 |
| 工位二照明 | 低角度条形光 | 垂直于拉丝或加工纹理方向 |
| 工位三照明 | 同轴光 | 镜面高光外观,减少现场环境影响 |
| 粗检候选区上限 | 每图200个 | 超过即触发异常提示,绝不让候选区无上限堆积 |
| 细分类输入尺寸 | 128×128像素 | 兼顾小缺陷细节与推理速度 |
| 判定规则 | 按机型独立维护 | 可视化面的划伤、装配面的划伤阈值不同 |
有人问分辨率怎么算出来的。思路很简单:假设视野宽度是50毫米,传感器横向像素数是5000,那么单个像素对应0.01毫米。要让0.1毫米的最小缺陷至少有3个像素覆盖,这个配置刚好够用;如果视野更大或缺陷更小,就往上加分辨率。这套逻辑虽然基础,但很多方案在立项时根本没算过,导致后面越调越费劲。
3.3 闭环迭代:当天误报当天进训练集
架构跑起来之后,真正的体力活在于数据回流。产线每天都在自然产生两类极其珍贵的样本:一类是误报,也就是系统拦截了但人工复判为OK的工件;另一类是漏报,发生在人工抽检或客户端反馈里。
我们的规矩是:**误报图当天追加为负样本,漏报图当天追加为正样本,每周做一次增量训练加回归测试。**现场质检员在复判终端上只需要点三个标签——OK、NG、疑似,点完以后数据自动进入待标注队列,算法工程师第二天上班直接处理。
这套流程看起来不难,但执行起来会暴露很多管理问题。以前我们攒样本是按“周”甚至“月”来算的,等数据够了再训一次模型,结果发现产线的材质、光源、机台状态早就变了,旧数据对新场景帮助有限。改成当天回流之后,模型每次迭代都在“吃”最新鲜的问题,针对性好很多。
我这里补一句:增量训练一定要配回归测试。每次训完新模型,必须拿过去两周的全量历史图像重跑一遍,确认之前的缺陷没有“回潮”。否则这个模型可能对今天的误报修好了,却把上周一个已经解决的漏检又放出来了。
4. 换型首月的实测数据与两个难啃的现场问题
4.1 首月数据对比:漏检率和过杀率的变化
在这个3C外壳项目上,传统单模型方案运行了将近四周,之后切到TVA架构再跑四周。因为中间存在人工复判流程,我们把几种核心指标做了对比:
| 指标 | 重构前(单模型) | 重构后(TVA) | 说明 |
|---|---|---|---|
| 漏检率(人工复检口径) | 0.6% | 0.15% | 以全检加抽检结果为基准 |
| 过杀率(复判后放行占比) | 9.5% | 2.8% | 每次拦截后由人工确认 |
| 换型调试时间 | 半天到一天 | 2~4小时 | 主要是更新样本库和判定规则 |
| 新增缺陷的模型迭代周期 | 攒样本数周 | 当天收集、周内更新 | 靠回流闭环 |
| 现场投诉/复检压力 | 高 | 明显下降 | 判断依据更透明 |
需要说明的是,这是单一项目的数据,不同材质和不同产品形态差异会很大。它的意义不在于“TVA一定能把漏检率降到多少”,而在于我们从结构上把指标的波动压住了:换型不再是一场灾难,新增缺陷也不再意味着整个方案推倒重来。
4.2 排查链路实录:拉丝纹理为何被当成划伤
首月跑得还算顺利,但第二个星期就撞上一个硬问题:换型到拉丝铝外壳之后,过杀率从2.8%一路飙到7%。终端显示的原因高度集中,几乎都是“划伤”。
排查链路是这样的。第一步,先把被判为划伤的图像全部拉出来看。结果发现,大量候选区域其实是拉丝纹理本身的亮线。拉丝方向与低角度条形光方向垂直时,每条丝纹都会形成高亮反射,视觉效果和浅划伤极度相似。
第二步,看训练样本。我们把样本分布调出来,发现训练集中“光滑表面”的照片占了绝大多数,真正包含拉丝纹理的负样本只有5%左右。模型没见过那么多“纹理亮线”,自然会把它们当成异常。
第三步,看特征分布。把拉丝亮线样本和真实划伤样本的特征映射出来之后,我们注意到一个关键差异:拉丝产生的亮线梯度方向高度一致,基本沿同一方向排布;而真实划伤的方向比较分散,深浅变化也更随机。
第四步,补规则而不是只硬训模型。我们在判定引擎里增加了一条方向校验:当候选缺陷方向与拉丝主方向夹角小于阈值时,只有亮线长度和深度同时超过标准才判NG,否则进入人工复检。同时重新采集了两百多张拉丝面图像加入训练集。
第五步,回归验证。拿历史两周的误报图像重新评估,过杀率回到2.6%,而且没有新增漏检。
这次排查让我印象很深,因为它告诉我们:出现误报的时候,不要急着骂模型,先把“信息是在哪一层断裂的”找出来。成像、样本、特征、规则,四层逐一排查,大多数问题都能定位。
4.3 第二个坑:镜面反光伪影被当成真实缺陷
另一个印象深刻的问题来自高光黑色外观件。上线第一天,粗检模块就疯狂报警,候选框大量集中在视野边缘的固定位置。细分类模型把这些候选框里的边缘纹理变化判成了“压伤”。
这批“压伤”如果按缺陷处理,过杀率会直接爆表。我们停线排查后发现,问题的根源很微妙:反光光斑是环境灯在工件曲面上的投影,每件产品拍照时都会在同一个位置出现,但它不是缺陷,而是光学伪影。
光靠细分类模型很难区分这种伪影,因为它的局部纹理和真实压伤太像了。我们的解法是“多视角一致性校验”:同一个真实缺陷会在多个工位、多个光源角度下同时被检出,且空间坐标基本一致;而反光伪影往往只在一个光源角度下出现。于是规则里增加了一条:候选区如果只在单个工位检出,且坐标不与其他工位产生关联,就标记为环境伪影并过滤掉。
这个方案上线以后,那种固定位置的反光报警基本消失。这件事再次验证了一个观点:很多“算法解决不了”的问题,其实是因为没有把物理世界的信息引入决策链。多一个视角,多一次光源切换,比给模型加一百层参数都管用。
5. 给想复刻这套架构的团队几句实在话
5.1 先统一“漏检率”的口径,否则团队会吵到怀疑人生
这是我最想提醒的一点。我们刚上线的时候,算法、生产和品质对“漏检率”的理解完全不一样:有人按质检员复检数算,有人按客户端退回数算,还有人按抽检比例反推。同样的数据,有人算出0.1%,有人算出1%,两边还都认为自己没错。
所以在项目一开始就要把口径定死,建议至少固定三个指标:
- 漏检率:人工复检或抽检中发现的NG件数 / 对应样本总数。
- 过杀率:复判为OK的拦截件数 / 总拦截件数。
- 换型时间:从切换机型到设备稳定运行所花的时间。
口径统一之后,算法工程师和生产主管才能在同一张报表上对话。否则所有争论都会变成“你们算得不对”的无意义内耗。
5.2 给现场留一条“人工复判通道”,别让算法一锤定音
很多检测项目上线后,被判NG的工件直接流入废品箱,导致两个问题:一是误杀的工件无法挽回,二是误报样本永远进不了训练集。这等于让系统闭着眼睛跑,越跑越脆。
我们的做法是设置复判工位。系统拦截的工件先到人工复判区,质检员确认OK的返回产线,确认NG的登记缺陷类型。这条通道表面上看多了一个人工环节,实际上它既降低了过杀带来的物料损失,又源源不断地为算法提供标注数据。没有复判通道的检测系统,后期迭代速度会慢一个数量级。
5.3 模型版本按机型管理,别指望一个模型通吃
不同材质、不同光源、不同机型的图像特征差异太大,指望一个模型“通吃”所有产品是不现实的。我们把模型按产品族拆成多个基线版本,新机型从最接近的基线复制出来做微调,每个版本都有独立的样本库和判定规则。
上线之前必须做历史回归:拿新模型跑一遍过去两周的全量图像,确认它在新老问题上都不劣化,才允许发布。一旦现场出现异常,还能一键回退到上一个稳定版本。这套版本管理机制看起来传统,但在快速换型的产线上非常管用,它能保证“改进”和“稳定”不互相牺牲。
我特别想强调的一点是,TVA三层架构最大的收益其实不在准确率数字变好看,而在于团队终于能正常配合了:光学工程师知道自己要为什么样的图像负责,算法工程师不再整天给“万能模型”做救火,现场品质也有明确的复判流程。如果你现在正被漏检率和过杀率两头夹击,我建议先别急着换更大更贵的模型,而是把检测链路拆成“成像—召回—细判—语义—回流”五段,看看信息是在哪一段丢的。这套架构不一定适合所有场景,但这个排查思路我自己用下来,相当值。