ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

让AI看得见:PCB视觉检测与缺陷识别全链路实践

让AI看得见:PCB视觉检测与缺陷识别全链路实践 1. 先回答一个问题为什么辅助系统必须会长眼睛1.1 从BOM比对到焊点检查哪些需求逼着我上视觉做硬件设计辅助系统做到第二期我遇到的最大的坎不是算法不是推理能力而是输入数据太贫瘠。前期我们做的知识库和规则引擎跑得挺好工程师问“这个电源模块的输入电容应该放多大”“这个接口的ESD保护器件选型合理吗”它都能给出像样的答复。可一碰到实际问题——板子已经贴好片、摆在调试台上——它就哑了。原因很简单它看不见。你问它“这块板子上哪个电阻焊歪了”它只能回你一句“请上传图片”。但上传图片之后呢它还是看不懂。所以第二期的主题就一句话给这个系统补上视觉感知能力。我把它叫做“让AI看得见”。这个“看得见”不是指接一个摄像头就能截图而是指从物理世界的电路板到一张含有多层语义的结构化检查报告中间整整一条链路的工程实现。先说说我具体被哪些场景逼到必须上视觉的。第一是回板检查。PCBA贴片回来后第一件事是核对元件。一块中等复杂度的板子几百个料靠人拿放大镜一个个对丝印、对位置、对极性方向眼睛真的会花。我有一次数电阻数了三遍三个数第四遍才确认原因是有两个0201的电阻并排挨着肉眼几乎分不清边界。第二是焊接质量抽检。虚焊、桥连、立碑、少锡这些问题在显微镜下才能看清楚但靠人盯屏幕看一整天注意力衰减得非常快。我记得有个同事看了一下午AOI图下班时跟我说他觉得自己眼睛里面全是锡膏的青色反光。第三是装联复盘。一旦出现功能异常工程师会拿着万用表到处量但很少人会回头去系统性检查整个板的贴装质量。如果你能快速把整板状态记录成一份带位置坐标、带元器件代号、带缺陷类别的报告哪怕只是作为排查前的背景信息也能省掉大量定位问题的时间。这三个场景本质上都指向同一个能力让系统能够把真实板卡图像和设计数据关联起来并输出可量化的判断。这也是“AI硬件设计辅助系统”里“看得见”的真正含义——它不是给AI装上一只眼睛就完事而是让它能像硬件工程师一样对着实物做检查、做对比、做判断。1.2 “看得见”不等于“看得懂”一张图像到结构化结果的路有多长很多人以为视觉模块的核心就是目标检测模型输入一张图输出几个框和标签完事。我第一次也这么想后来发现自己太天真。你随便拍一张PCB高清照丢给目标检测模型它能告诉你哪里有电阻、哪里有电容、哪里有芯片。但如果你问它“这里的焊点少锡了没有”“这个电阻的方向和BOM丝印是否一致”它就答不上来了。更别说“这两个相邻引脚之间是不是桥连了”——这需要亚毫米级的空间分辨率普通拍照根本不行。从原始图像到一份能用的检查报告我实际走完的路是这样的图像采集解决“拍得清、拍得全、角度一致”的问题图像预处理解决畸变、反光、亮度不均的问题单元定位在图中找到每个元器件的外接框和中心点特征抽取在元器件局部区域里提取焊点、丝印、引脚等细节规则判定把“模型输出的坐标和置信度”变成“合格/不合格/待确认”的结论结构化输出生成带有位号、坐标、缺陷类型、置信度、原图截图的报告这里面真正花费时间最多的不是第三步的模型训练而是第一步的采集链路和第五步的规则判定。我一直觉得视觉落地的难度不在模型而在模型之外的工程。就像人看东西眼睛只负责采光大脑才负责理解。你要让“大脑”稳定地理解工业画面前面的光学条件和后面的判定逻辑得先稳定。所以这篇文章我会按照自己做过的路径来写先讲硬件选型和图像采集再讲识别与判定逻辑最后放一组真实的实测数据和调优记录。涉及代码的部分我用Python片段演示所有方案都能在一个普通硬件工程师的办公桌上复现。2. 视觉模块的硬件选型与图像采集稳定压倒一切2.1 为什么没选普通USB摄像头帧率、畸变和触发时延一开始我想的是“省事”买个几百块的1080P USB摄像头接电脑完事。结果第一次测试就翻车了。翻车的点有三个。第一个是畸变。普通USB摄像头用的是广角镜头边缘畸变非常明显。我拍一张A5大小的板子板子中央和板子边缘的同一颗0402电阻在图像里大小差出一截。这种畸变对于人眼看图没什么影响但对目标检测模型来说等于引入了不规则的空间扭曲——模型可能做得出色但你的检测框和元器件实际位置的对应关系会非常不准。第二个是自动曝光和自动白平衡。USB摄像头默认开着自动曝光这意味着它会在画面里出现大面积高亮焊盘时自动调暗在光线不足时自动调亮。每帧图的亮度都在变模型输入分布不稳定直接后果就是置信度时高时低误检率忽上忽下。第三个是触发时延。硬件系统里我们经常需要“拍一下等图像稳定再取图”这样的时序。但USB摄像头的帧缓存和驱动层时序是黑盒你很难做到精确的软硬件同步。对静态板卡拍照还好但如果你未来想做在线检测传送带一停一问触发信号到图像定格之间的延迟不稳定是很致命的问题。所以我最后选了工业相机定焦工业镜头可控光源的组合。具体参数参考如下项目普通USB摄像头我选用的工业相机方案传感器1/2.7英寸 CMOS1/1.8英寸 CMOS分辨率1920×10802592×1944500万像素镜头广角定焦畸变明显C接口定焦工业镜头畸变0.3%曝光控制自动不可关手动快门/增益完全可控触发方式不支持外部触发硬件GPIO软触发接口USB 2.0GigE Vision / USB3 Vision这套方案的成本大概是把USB摄像头的预算乘了一个10但我认为这钱不能省。视觉系统的稳定性是由光学链路的确定性决定的你连图都拍不稳后端的模型再怎么调都是沙上建塔。安装的时候有几个细节我在第一版没注意后来返工了。一个是相机的光轴要尽量垂直于板面否则透视变形会带来定位误差第二个是相机镜头到板面的距离要固定能锁死就锁死因为目标检测模型的检测框尺寸和实际毫米尺寸的换算依赖这个固定距离。2.2 光源和支架这块最容易被低估我见过太多人花大钱买相机却拿一盏台灯当光源然后发现模型精度上不去还以为是算法不行。在工业视觉里光源的重要程度不亚于相机本身。原因是电路板上大量存在高反光的焊盘、铜箔、金手指和芯片表面直接用环境光拍会出现大面积的镜面反射焊点和引脚细节被高光淹没。我的方案是低角度环形光源加漫射板。低角度环形光的好处是光线从四周以较平的角度照射板面高反光表面会把光反射到远离镜头的一侧而焊点、字符、引脚这类漫反射特征会显得更清晰。说得直白一点它能把“反光刺眼”变成“细节清楚”。漫射板是用来把点光源打散成柔和面光源的这样可以避免LED灯珠在焊盘上形成一粒一粒的独立高光斑。我第一次没加漫射板拍出来的板子上全是密密麻麻的小白点模型的loss怎么降都降不到预期值后来排查了半天才发现是照明不均导致的高光斑干扰。支架方面我买了一个小型的龙门架相机固定在顶部板卡放在载物台上左右两侧各放一路条形LED作为补充照明。载物台我贴了哑光黑植绒贴纸减少背景反光。板卡压平用四个弹性压片边缘贴了防滑胶垫。还有一点很重要拍摄环境要固定。我专门留了一个角落拉上遮光帘所有板卡的采集都在同一光照条件下完成。这不是吹毛求疵——模型训练的时域分布和推理时的时域分布越一致实际表现越好。你在推理环境里改变了光照方向或亮度再好的模型也可能瞬间失灵。2.3 采集服务的工程化软触发、多角度联动与图像命名规范硬件准备好之后我面临的问题是从“能拍照”到“能稳定批量拍照”。这里我写了一个Python采集服务做了三件事。第一件事是软触发的稳定化。虽然工业相机支持硬件触发但在我们这种“人把板子放上去按一下软件按钮拍照”的半自动场景软件触发加上固定延时已经足够。我在触发后等500毫秒等镜头和光源的状态稳定下来再执行抓帧。实测下来图像一致性很好。核心代码大概长这样import cv2 from pypylon import pylon # 基于GigE Vision相机的SDK camera pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice()) camera.StartGrabbingMax(1) camera.ExposureTime.SetValue(8000.0) # 微秒级曝光时间锁定 camera.Gain.SetValue(0.0) # 增益固定为0避免噪点失控 frame camera.RetrieveResult(5000, pylon.TimeoutHandling_Return) if frame.GrabSucceeded(): img frame.Array cv2.imwrite(output_path, img) frame.Release() camera.StopGrabbing()这里我强调一下曝光时间和增益必须写死。第一次测试时我没锁定自动增益结果同一块板在不同环境照度下拍出的图像明暗差异很大导致后续识别精度波动。工业相机调手动模式曝光时间根据现场亮度定一次之后就别再动它。第二件事是多角度采集。一块PCB的信息量太大俯视图只能看到元件面和丝印焊盘反光也只有在特定角度才看得出来。我做了一个四角度采集垂直俯视、左侧15度、右侧15度、前侧20度。四个角度分别用于不同的检测项——垂直角度用于元件位置和极性识别侧向角度用于焊点饱满度判断前侧角度专门拍BGA和QFN这类底部引脚器件的侧面。第三件事是图像命名规范。这在后面做数据集管理时救了我的命。每张图的文件名格式是这样PCB_20240512_PROJ123_BD001_TOP_ANGLE90.jpg依次是项目代号、样板编号、板面TOP/BOTTOM、拍摄角度。元数据我再单独维护一个JSON存相机位姿、曝光参数、光照配置。没有这套规范后面整理训练集的时候你会疯掉的。我真的见过有人把千张图随意命名成IMG_0001.jpg最后要重新拍照。3. 核心识别能力元器件定位与缺陷检测的实现逻辑3.1 目标检测模型的选型与训练数据准备图像链路打通后下一步是让模型能“看到”元器件。我的目标很明确在板卡俯视图上把每个可识别的分立器件和无源器件框出来输出类别和位置。类别包括电阻、电容、电感、二极管、连接器、IC芯片、晶振、保险丝等。模型选型我直接选了YOLOv8。原因不是它最先进而是它工程化成熟度最高导出ONNX方便、部署无坑、小尺寸模型跑在普通PC的GPU上就能实时推理。我用的m模型输入分辨率640×640单张推理时间在RTX 3060上约15毫秒完全够用。训练数据的构建是整个环节里最费功夫的。我没有从零找公开数据集而是结合了三条路手工标注自有板卡图像约80张每张图上有几十到上百个元件累计标注框超过8000个用公开的PCB元件数据集做预测练先让模型学会通用特征针对我们最常用的几种封装0402、0603、0805、SOT-23、QFP-48补充合成数据合成数据这步我多说一句。我自己写脚本把元件符号贴到不同角度、不同光照的PCB背景图上生成了2000多张带标注的图片。虽然合成图跟真实图有差距但它极大提升了模型对旋转角度和遮挡情况的鲁棒性。标注工具用LabelImg和X-AnyLabeling都行我最后选了X-AnyLabeling因为它支持SAM辅助分割能快速生成高质量的标注掩码。实际标注的80张图里有相当一部分框是用它半自动打出来的。训练参数我直接给了个靠谱的基线再微调batch size 16epochs 300imgsz 640optimizer SGD学习率初始0.01配合cosine退火跑完后在验证集上的mAP50超过0.95mAP50-95在0.88左右。这个精度对元器件定位来说已经足够好。但我要泼一盆冷水模型只见树木不见森林它只知道哪里有电阻、哪里是电容不知道这个电阻该不该在这、方向对不对、焊得好不好。这些判断属于更高阶的语义理解单靠目标检测模型做不了。3.2 焊接缺陷检测为什么单纯靠分类模型会翻车焊接缺陷检测比如虚焊、桥连、立碑、少锡、多锡、偏移不是“是/否”的二分类问题。它本质上是一个空间几何与区域特征联合判定问题。我用过一段时间ResNet分类模型专门训练一个分类器判断“这个焊点正不正常”结果在测试集上准确率能到97%一上真实板卡就打回原形。为什么因为真实板卡上的焊点在光照、角度、器件布局上的变化远超训练集。分类模型学到的是“看起来像缺陷”的表象而不是“焊点形状偏离设计形态”的本质。后来我换了一种思路先用图像分割把焊盘和焊料区域分离出来再做量化分析。我改用了轻量级分割模型基于UNet的剪枝版输入是元件局部区域的图像输出是焊料区域的掩码。然后基于掩码提取以下特征焊料覆盖面积占焊盘面积的比例判断少锡/多锡焊料区域的轮廓凸性和圆形度判断虚焊/润湿不良两个相邻焊盘之间是否存在连通的焊料区域判断桥连焊料区域质心与焊盘中心的偏移量判断偏位焊点高度通过侧视角图估算判断立碑这些特征再送进一组规则判定器输出结论。这一步的转变让整个系统从“看起来聪明”变成了“真的可解释”。3.3 规则判定层把“模型输出”变成“可执行的检查报告”模型输出的是一堆坐标框、类别、置信度和掩码硬件工程师要的不是这些而是“C39这个电阻方向装反了”或者“U2第5脚疑似桥连”。所以我在模型之上加了一个规则判定层。这个层的思想是把设计阶段的数据拉进来做交叉比对。我们系统里本身有PCB设计文件解析模块能导出该板所有元件的位号、封装、中心坐标、旋转角度、所属网络。规则层把这些设计数据和视觉模型的输出对齐。对齐的关键步骤是坐标系标定。我通过几个已知位置的定位标记拼板工艺边上的特征点计算图像坐标系和设计坐标系之间的单应矩阵然后把模型输出的像素坐标转换成设计坐标系坐标。有了这个转换规则层才能回答“这里检测到的电阻到底是设计文件里的R12还是R13”。对齐之后剩下的判定逻辑就没那么玄学了。举例说明# 伪代码方向极性检查以二极管为例 for diode in inference_results.diodes: design_rotation design_db.get_part_rotation(diode.bit) # 设计给定角度 visual_rotation estimate_visual_rotation(diode.crop_img) # 图像估算角度 delta normalize_angle(design_rotation - visual_rotation) if abs(delta) 15: report.add_issue( bitdiode.bit, typepolarity_error, detailf设计角度{design_rotation}°实际角度{visual_rotation}°偏差{delta}° )类似的少锡判断就是算一个面积占比阈值桥连判断就是检查两个相邻焊盘掩码的连通域面积。每个判断都对应一条可解释的规则而不是一个大模型的黑盒结论。这也是我反复跟团队强调的AI负责把像素变成特征规则负责把特征变成判断。两者各司其职。4. 实测复盘样板识别结果与参数调优记录4.1 测试方案与量化指标整套系统搭完后我在一块真实的样板板上做了完整的验证。这块板是一块电源管理小板尺寸大约80mm×60mm有112个元件包括47个电阻、31个电容、9个二极管、5个IC、6个连接器、还有电感和保险丝等。我进行了三轮测试。第一轮是直接拍图识别第二轮针对第一轮暴露的问题做参数修正第三轮是针对光源和曝光修正后的复测。还有个对照项让一位有三年硬件经验的工程师用同样时间手动检查一遍记录他发现的缺陷数量、检查时间和漏检情况。评估指标我用了四类元件定位识别率所有元件里有多少被正确检测并分类缺陷检出率我们预先在样板板上人工制造或已知存在的缺陷里系统检出多少误报数系统报告但实际不存在的缺陷数量单板检测耗时从放上板卡到输出报告的完整时间4.2 第一轮测试的结果和翻车现场第一轮结果还算能看元件定位识别率到了96.4%。112个元件里漏检了2颗0201小电阻误检了1个把一颗MLCC电容认成了钽电容。这属于正常水平0201封装太贴近板面在640分辨率下像素数不多漏检可以理解。但缺陷检测的结果就比较惨了。我们预埋了10个缺陷包括2处桥连、3处少锡、2处立碑、1处焊料空洞、1处电容偏移、1处极性反第一轮只检出了4个漏了6个误报了17个缺陷。误报主要集中在焊盘边缘的正常氧化色差上被分割模型当成少锡还有就是两个相邻排阻之间的正常沟槽被识别成桥连。这轮测试让我明白了一个道理漏检不可怕可怕的是误报太多。误报多了工程师就不会信你的报告整个辅助系统就变成了一个“狼来了”的工具。正常情况下一个检查系统宁肯漏检也不该乱报——漏检最多是没发现误报多了是摧毁信任。4.3 三类高频问题的根因分析与调优我把误报和漏检的原因归成三类逐一处理。问题一光源不均匀导致焊盘边缘伪阴影。我原来以为增加了漫射板就万事大吉但测试中发现板子边缘区域的光照还是比中央暗一截。边缘焊点的分割结果里减光区域被误判为少锡。这个问题的排查方法很简单把同一张图跑出来的分割掩码和原图叠加凡是在板边出现的缺陷标签全部人工复查一遍。调优动作把环形光源的功率提高了20%并在左右条形灯上增加柔光罩和亮度补偿。同时把曝光时间从8000微秒提高到10000微秒提升暗部细节。这块调完之后板边缘的误报大幅下降。问题二焊盘氧化色差被当成少锡。这一点比较恶心。焊盘表面轻微氧化时颜色发暗发黄和少锡的暗区在灰度上非常接近。人眼能区分是因为有上下文——周围焊点都亮就它暗那可能是少锡周围焊点都有类似的暗色那就是氧化。但我们的分割模型只看局部区域缺乏全局上下文。调优动作我给规则层增加了一个“同板比对”逻辑。把同一块板上所有同类焊盘比如所有0603电阻的两端焊盘的特征分布拉出来如果某个焊盘的暗区面积在统计分布中的z-score超过3才判定为疑似缺陷如果整板焊盘都暗则判定为氧化不报缺陷。这个改动一下子把少锡误报从11个降到了2个。问题三0201小尺寸元件漏检。两颗漏检的元件都是0201电阻单颗尺寸只有0.6mm×0.3mm。在640分辨率下一个0201元件大约只占10×10像素。这个尺度下即便是YOLOv8m也容易把特征和焊盘纹理混在一起。调优动作除了用原图做全局检测外我增加了一个“高分辨率局部放大”分支。先用全局模型检测出所有焊盘密集区再用这些区域的2倍放大裁片跑同一个模型。相当于做了个简单的高分辨率Pyramid把小元件检测率拉到了98.2%。两颗漏检都找回来了。4.4 参数修正后的最终成绩调优完成后我做了第三轮复测指标第一轮第三轮元件定位识别率96.4%98.2%缺陷检出率4/1010/10误报数173单板检测耗时45秒38秒说实话有些缺陷能被全部检出我既高兴也清楚有运气成分——我们预埋的缺陷形态都比较典型真实生产环境里的缺陷形态会复杂得多。但至少这套管线是能用的38秒出一份报告检出10处问题只误报3处这已经能给硬件工程师节省大量时间。4.5 几个值得记住的调优经验这台系统跑起来之后我把整个调试过程复盘了一遍整理出几条对所有人都有用的经验。第一不要一上来就微调模型。先确保输入图像稳定再调光源然后看规则层最后才轮到模型。我见过太多人在模型结构和超参上折腾半天结果是同一个问题拍照亮度不一致。第二误报要分类治理不要一刀切调阈值。比如少锡误报和桥连误报成因不同单纯降低灵敏度只会让真缺陷也漏掉。正确做法是回到图像层面分析为什么误报然后解决成因。第三规则层一定要保留原始的判定依据。当一条缺陷被报告出来时报告里必须能追踪到“哪个焊盘、什么特征值、对比了谁、因为什么超限”。否则工程师复查时会骂娘。5. 从“看得见”到“用得起来”视觉模块与辅助系统的完整衔接5.1 识别结果的结构化让字VDC报告能直接被拆解和使用很多人在视觉项目收尾时都会忽略最后一步——结果的结构化。模型的输出再准如果只停留在“图片上有几个框”的层面对业务系统其实没什么用。我的做法是把所有检测结果统一封装成JSON形态的结构化数据一份板卡对应一个文件。这个JSON文件里包含以下内容{ project_id: PWR-BOARD-202405, board_sn: BD001, factory: 批次A-20240512, total_parts: 112, detected_parts: 110, parts_missing: 2, check_time: 2024-05-12 14:23:11, image_links: { top_90: img/BD001_top90.jpg, left_15: img/BD001_left15.jpg, right_15: img/BD001_right15.jpg }, defects: [ { id: 1, bit: R12, type: solder_bridge, confidence: 0.92, position_mm: [12.3, 45.2], attributes: { bridge_area_px: 128, neighbor_part: R13 }, crop_image: crops/R12_bridge.jpg, rule_trace: { mask_condition: adjacent_mask_connected_area_exceeds_50px, threshold_value: 50, actual_value: 128 } } ] }这个结构有几个设计意图。每条缺陷都带位号bit工程师可以直接在设计文件里定位到具体器件而不是在照片里找position_mm字段是设计坐标系下的毫米坐标方便跨工具联动crop_image字段存了缺陷局部截图工程师点开报告时直接看到图不用再去原图里找rule_trace字段记录的是判定依据包括阈值和实际值这样误报的时候工程师一看就知道是哪个规则误判了这个JSON设计我最满意的一点是把“AI的判断”和“判断的理由”捆在一起。工程师拿到报告时不是说“AI说这里有缺陷”就直接接受或拒绝而是能一眼看到AI的依据快速判断是否采信。这才是辅助系统的本质——它辅助工程师决策而不是取代工程师决策。5.2 视觉结果如何回灌给上层智能体有了结构化的检查报告接下来就可以和上一期做的知识库、规则引擎、大模型Agent打通了。我做了这样一个接口层把识别结果统一转成“事件”消息推给辅助系统的主服务。主服务再根据事件类型触发不同的后续动作。实际跑通的链路包括当检测到极性错误时自动调取该器件的规格书定位到极性标识的说明页随报告一起推送当检测到多个同区域少锡缺陷时自动归并成一条“疑似回流焊温度偏低”的工艺提醒并把相关的工艺参数文档链接附上当检出漏贴元件时自动比对BOM表看是设计遗漏还是贴片漏贴同时输出替代料推荐这几条自动化操作看起来很神秘其实核心就是视觉模块负责事实规则层负责定性知识库负责辅助决策Agent负责组织语言和推送。每一层做它擅长的事情组合在一起才有真正可用性。比如桥上类型的错误工程师看到报告时会希望知道是“短接到了哪个网络”。我从设计文件里拿到R12和R13的引脚网络发现桥连位置两侧分别是3.3V电源网络和GND网络于是报告里追加了一行此桥连可能导致3.3V对地短路。这种结论不是视觉模型能直接给的但视觉模型给出的位置信息成了触发这个结论的钥匙。5.3 当前方案的成本、边界与后续规划最后说一下这套方案的成本和边界。硬件成本大概这样工业相机3000元级别镜头800元环形光源加支架合计约1500元漫射板和载物台做了个小工装约600元。软件部分所有模型都是开源的推理在自有GPU上跑没有额外的API费用。这些钱对个人开发者来说完全能承受。但边界也很明显。这套系统目前只能在静态桌面环境下工作放上板、按钮、出报告。真正要做成在线AOI还需要考虑传送带触发、多工位同步、节拍控制那个复杂度至少翻三倍。其次它的检测项受限于我们标注过的缺陷类型如果你要做金手指划痕、孔内锡膏填充这类特殊检测目前实现不了。最后它对板卡尺寸有上限超出相机视野的大板需要拼图算法这部分我还没做。后续我计划做两件事。第一是把侧视角和俯视角的特征做跨视角融合这样能对焊点高度有更准确的三维估计改善立碑和虚焊的判定。第二是把训练数据扩充到更多板卡类型目标是让模型识别各种常见封装的能力更鲁棒同时做迁移学习的评估——看看换一块完全陌生的板子系统要多少张标注图才能重新达到90%以上的识别率。我个人对“让AI看得见”这一期的成果评价是它终于不再是个只会聊天的系统而是一个能对实物世界产生感知并能输出可信结论的工具。虽然离全自动、高可靠、工业化还有距离但作为辅助系统它已经能在实际工作中帮我节省出真金白银的时间了。
返回列表