news 2026/10/19 9:41:00

基于YOLO26的PCB缺陷检测系统:从训练到部署全流程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于YOLO26的PCB缺陷检测系统:从训练到部署全流程实践

去年底有个做电子制造的兄弟找我,说他们产线上AOI设备误报率太高,焊点附近的铜箔缺陷总是漏检,人工复检速度又跟不上。聊到最后,核心需求就一句话:能不能拿深度学习模型试一把,直接在光学检测环节就把缺陷框出来。这个需求在PCBA行业非常普遍,也正好是我一直想做的方向——用YOLO26训练一套6类PCB缺陷检测系统,覆盖缺孔、鼠咬、开路、短路、多余铜、伪铜这六种常见问题,训练、部署、界面一条龙,还顺手做了中英文双版,方便国内产线和海外客户两种场景切换使用。

这套系统不是一个只有训练脚本的玩具。完整的源码里包含数据预处理、训练脚本、推理检测程序、PyQt5图形界面、模型导出脚本和效果演示视频。不管你是刚接触目标检测的视觉方向学习者,还是在工厂里想落地AI质检的工程师,都能从中找到可以直接抄作业的部分。下面我按实际做这个项目的顺序,把从数据到部署的完整链路拆开讲。

1. 项目拆解:为什么是YOLO26和这6类缺陷

1.1 6类缺陷的定义与识别难点

PCB缺陷检测之所以难,第一难在缺陷本身形态差异大。我这次锁定的六类缺陷,每一类的视觉特征和产生原因都完全不同。

缺孔(missing hole),指的是板上本该打孔的位置没有钻透,或者被油墨、阻焊剂堵住,在光学图像上的表现就是焊盘或过孔位置出现异常的反光区域,和正常孔对比起来没有规则的环形阴影。鼠咬(mouse bite)这个名字很形象,线路边缘出现一个向内凹陷的缺口,像被老鼠啃过一口,主要原因是蚀刻液喷洒不均,局部过蚀。这个缺陷尺寸很小,边界模糊,是六类里检测难度比较高的。开路(open circuit)是铜箔线路断裂,信号走不通,成像特征是本该连续的高亮铜线中间出现暗色断口。短路(short)和开路相反,是两条不该相连的线路之间出现了多余的铜连接,特征是两条平行线之间出现桥接状的亮斑。多余铜(spurious copper)是蚀刻不彻底留下的铜箔残留,形状不规则,散布在基板表面。伪铜(copper defect)这个名称有点误导,本质上是铜面瑕疵,比如铜箔表面的划痕、凹陷或氧化斑,特征是铜面上出现不均匀的明暗区域。

识别难点在哪里?缺孔和伪铜都和正常铜面的差异很微妙,容易和背景噪声混淆。鼠咬和开路属于小目标,在640分辨率下可能只有十几个像素。短路又和多余铜在形态上有相似性,需要模型区分语义上“不该连但连上了”和“本来就是多余残留”的区别。好在深度学习目标检测不靠人工设计特征,只要数据给足,模型自己会去学习这些细微模式。

1.2 为什么选YOLO26而不是旧版YOLO或其他模型

PCB缺陷检测是产线实时场景,对推理速度的要求很刚性。二阶段检测器像Faster R-CNN虽然在精度上有优势,但在同一块GPU上跑640分辨率输入,帧率通常只有YOLO系列的几分之一,产线上根本顶不住。而老版本YOLO在特征提取网络上相对薄弱,对极小目标的召回率不太理想。

YOLO26是目前YOLO系列里比较新的一代,我拿到这套项目时看重的就是它在几个方面的改进:主干网络采用了更高效的C2f类模块,特征复用能力更强,颈部结构对多尺度特征的融合更细腻,检测头沿用了anchor-free的解耦设计,把分类和回归分成两个分支,收敛更快。这些改进落到PCB检测场景里,最直接的效果就是鼠咬、开路这类小目标漏检率明显下降。

当然,选型不是只看版本号。我还对比过同系列其他变体,结论是YOLO26在速度和精度的平衡点上更适合这个场景。如果产线用的GPU算力很弱,可以考虑剪枝版本或更低分辨率输入,但训练流程和代码完全不用动,这也是这套体系生态成熟的好处。

1.3 中英文双版的设计价值

这个项目做了中英文双版,不是简单翻译几个按钮。国内工厂的质检员习惯中文界面,而设备整机出口或外资工厂往往要求英文界面。如果界面语言写死在代码里,每换一个现场就得改代码重新编译,非常痛苦。我在设计GUI时把所有文本都收进了一个语言包模块,用一个字典管理中英文映射,运行时根据配置或按钮一键切换,不需要重启程序。

这个设计对源码的可维护性帮助很大。后续如果要做日语、韩语版本,只需要在这个语言包里加一组映射,完全不需要动界面逻辑。

2. 数据准备与预处理:模型能不能学好的关键基础

2.1 数据来源与标注格式转换

数据集用的是开源社区常用的PCB缺陷数据集,包含690张左右的板卡图像,六类缺陷都有标注,总共约1385个缺陷实例。这个数据量听起来不大,但对目标检测任务来说,配合数据增强和预训练权重,已经能训练出一个效果可用的模型。

拿到原始数据后要先确认标注格式。这个数据集给的是VOC格式的XML标注,而YOLO系列训练时需要的是TXT格式,每张图对应一个文本文件,每行一个目标,格式是:类别序号 中心点x坐标 中心点y坐标 框宽度 框高度,所有值都归一化到0到1。转换脚本的逻辑很直接:读XML,提取每个目标的bounding box坐标,把绝对像素坐标除以图像宽高得到归一化坐标,然后按类别写入TXT文件。注意类别要从0开始编号。

这个转换过程看起来简单,但很容易栽跟头。XML里有的框坐标可能超出图像边界,特别是标注框贴边的情况,转换后会出现大于1的值,训练时容易报错或产生无效anchor。我的做法是在转换脚本里加一个clip操作,把所有坐标限制在0到1区间内,同时过滤掉宽高小于3像素的异常框,这些基本是标注误差,留着只会干扰训练。

2.2 数据增强策略与类别平衡处理

六类缺陷在数据里不是均匀分布的。缺孔和短路相对多一些,鼠咬、伪铜数量偏少。如果直接拿原始数据训练,模型会对少数类严重欠拟合。我的处理方案是两层:一是对少数类做样本复制或轻微扰动增强,相当于在训练时给这些类更多曝光机会;二是调整损失函数里的类别权重,给样本少的缺陷类型更高的loss贡献权重。

数据增强我用的是Mosaic、随机翻转、旋转、HSV色域扰动和模糊模拟。Mosaic把四张图拼在一起训练,一张图里能看到多个缺陷,等于变相增大了batch size,对提升小目标检测效果特别明显。HSV扰动模拟不同光源色温下的图像变化,因为产线上的光照条件不可能和数据集完全一致。模糊模拟用来对抗相机对焦偏差。

但增强也不能乱用。PCB图像和自然图像不一样,板卡上的线路是横平竖直的,旋转角度限制在正负15度以内就够了,转太多会让模型学到错误的空间先验。我调试的时候发现,旋转增强角度放开到90度后,模型对短路的检测精度反而掉了两个点,原因就是产线照片里几乎不可能出现大角度旋转的板卡。

2.3 数据划分与验证集构建

数据划分我用的是8:1:1的比例,训练集、验证集、测试集。关键是要按图像而不是按缺陷实例划分,避免同一张板卡的不同裁剪块同时出现在训练集和测试集里,否则评估结果会虚高。我在划分后额外做了一件事:统计各类缺陷在三个子集中的分布占比,确保每个子集里都有六类缺陷。如果测试集里恰好缺了鼠咬这一类,mAP指标会跳过这一类,看起来分数很高,实际落地时鼠咬全都漏检,这个坑一定要避开。

3. 训练配置与调参:让YOLO26在PCB数据上收敛

3.1 训练环境与超参数选择

训练用的是单块GPU,显存24G,PyTorch环境,CUDA和cuDNN版本要跟框架匹配。更具体的版本号我写在了源码的requirements.txt里,照着建环境就行。训练输入分辨率设为640,batch size设为16,这里有一个权衡:分辨率太高会拖慢训练和推理速度,太低又不利于小目标检测。640是YOLO系列的默认值,也是速度精度的均衡点。

学习率我用的0.01,配合余弦退火和3个epoch的warmup。warmup阶段让模型先用小学习率热身,避免一开始就大步长震荡。优化器先用SGD配合动量0.937,训练到后半程如果loss不再下降,我会换成AdamW继续微调,这在目标检测任务里是个很实用的技巧。EMA(指数移动平均)保持开启,它相当于对模型权重做滑动平均,能让验证精度更稳定,几乎零成本。

最大训练轮数设了200轮,开了早停机制,验证集mAP连续30轮不提升就自动终止。按我的经验,PCB数据集场景比较单一,通常120到150轮就能收敛,后面几十轮纯粹是在验证是否过拟合。

3.2 训练过程实录与loss变化解读

训练刚开始的前5轮,loss下降速度非常快,这是正常的,模型在快速学习前景背景的基本区分。到20轮左右,下降速度放缓,说明模型开始精细化拟合缺陷的边界。前50轮里我主要盯着训练集loss和验证集loss的差值,如果两者差距持续拉大,就是过拟合信号。

这里要提醒一句:训练曲线不是越平滑越好。Mosaic增强会在前中期引入较大的batch内图像差异,导致loss震荡,这是正常的。如果你看到loss曲线像心跳一样一上一下,不要慌,看整体的下降趋势和最终的验证mAP就行。

我这次训练结束时的结果:mAP@0.5大约0.96,mAP@0.5:0.95大约0.84。按类别看,短路、缺孔的AP最高,鼠咬和伪铜相对低一些。这个排序完全符合预期,小样本类别加小目标形态,识别难度天然高。

3.3 评估指标怎么看

目标检测评估不看单一指标,mAP@0.5和mAP@0.5:0.95各有意义。mAP@0.5表示IOU阈值0.5下的平均精度,是业界最常用的标准,反映框位置“大致对”时的精度。mAP@0.5:0.95则对框的定位精度要求苛刻得多,要求在多个IOU阈值下都保持高精度。PCB缺陷检测对缺陷位置的精确度有要求,因为后续的维修机械臂需要知道缺陷的准确坐标,所以我会更看重mAP@0.5:0.95。

还有一个容易被忽略的指标是每个类别的AP。只看整体mAP会掩盖单类缺陷失效的问题。我排查模型问题时,第一件事就是查看每类AP,哪类AP低就去补哪类的数据,这个习惯帮过我不少忙。

4. 推理部署与中英文界面实现

4.1 模型导出与推理加速

训练好的PyTorch权重不能直接上产线,第一步要导出为ONNX格式,再做TensorRT加速。ONNX是一个中间格式,相当于模型在不同推理框架之间交流的通用语言。导出时要注意设置动态轴,让模型可以接受不同分辨率的输入,同时把输出端的后处理逻辑一起导出,这样推理代码更简洁。

TensorRT是NVIDIA的推理优化引擎,能把模型编译成高度优化的计算图,在相同硬件上通常能带来2到4倍的加速。我用的是FP16精度模式,精度损失在可接受范围,而推理速度从纯PyTorch的30毫秒每帧降到了10毫秒左右。如果产线的GPU支持INT8量化,还能更快,但INT8对少数缺陷类别的精度影响稍大,需要先用验证集评估再决定要不要启用。

4.2 PyQt5界面的多语言切换实现

图形界面我用PyQt5写,整体布局是:左侧是图像显示区域,右侧是检测结果列表和参数控制面板。界面上要求两个功能:一是能加载单张图片或连接相机实时检测;二是中英文界面随时切换。

语言切换的实现不复杂。我把界面所有字符串做成了一个字典:

LANG_PACK = { "zh": { "window_title": "PCB缺陷智能检测系统", "btn_open_image": "打开图片", "btn_start_camera": "启动相机", "label_defect_class": "缺陷类别", "label_confidence": "置信度", "btn_switch_lang": "Switch to English", "status_ready": "就绪", }, "en": { "window_title": "PCB Defect Detection System", "btn_open_image": "Open Image", "btn_start_camera": "Start Camera", "label_defect_class": "Defect Class", "label_confidence": "Confidence", "btn_switch_lang": "切换到中文", "status_ready": "Ready", }, }

界面上每个需要显示文本的控件,都通过一个translate函数去字典里取值。点击切换语言按钮时,遍历界面上的所有控件重新设置文本。最关键的一步是切换后必须调用retranslate_ui来刷新界面,否则按钮文字变了,但窗口标题和提示信息还是旧语言。

还有一个细节,PyQt5默认字体对中文支持不好,容易出现方框乱码。我在程序启动时设置了全局字体:

font = QFont("Microsoft YaHei", 10) QApplication.setFont(font)

这样中文界面在所有Windows系统上都不会有乱码问题。Linux系统上换成WenQuanYi或Noto Sans CJK就行。

4.3 实时检测的线程模型

实时检测最怕界面卡死。如果直接在GUI主线程里跑模型推理,相机帧率稍微高一点,界面就会冻结,按钮点了没反应。解决办法是三个线程分工:主线程负责UI渲染和事件响应,相机线程负责采集图像帧,推理线程负责跑模型。帧数据通过队列传递,推理线程处理完一帧就把结果放回另一个队列,主线程定时从结果队列取数据刷新画面。

线程模型里有个经验之谈:队列长度要限制,比如最多缓存两帧。如果推理速度跟不上相机帧率,旧帧会被丢弃,保证界面显示的是最新结果,而不是积压的延迟画面。这个机制对产线场景尤其重要,因为相机的帧率可能是30帧,而推理速度只有10帧,不做丢帧处理的话,画面会越来越卡,最终卡死。

5. 源码结构与核心代码解析

5.1 项目目录结构

拿到源码后,第一件事是先花五分钟把目录结构看明白。这套项目的结构是这样组织的:

PCB-Defect-Detection/ ├── config.yaml # 全局配置文件 ├── requirements.txt # Python依赖清单 ├── data/ │ ├── images/ # 原始图像 │ ├── labels/ # YOLO格式标注 │ └── dataset.yaml # 数据集路径与类别定义 ├── scripts/ │ ├── convert_voc_to_yolo.py # VOC转YOLO格式脚本 │ ├── train.py # 训练入口 │ ├── detect.py # 单图/批量推理脚本 │ └── export_onnx.py # 模型导出脚本 ├── gui/ │ ├── main_window.py # PyQt5主窗口 │ ├── language_pack.py # 中英文语言包 │ ├── infer_engine.py # 推理引擎封装 │ └── resources/ # 图标与样式资源 ├── weights/ │ └── best.pt # 训练好的权重文件 └── utils/ ├── plotting.py # 结果可视化工具 └── metrics.py # 指标计算工具

config.yaml里集中管理所有可配置项,包括模型路径、输入分辨率、置信度阈值、NMS阈值、类别名称等。这样设计的目的很简单:换一个现场,只需要改配置文件,不需要改代码。

5.2 检测主流程核心代码解读

detect.py里最核心的一段是加载模型并执行推理:

from ultralytics import YOLO model = YOLO("weights/best.pt") results = model.predict( source="data/images/sample_01.jpg", conf=0.35, iou=0.45, imgsz=640, device="cuda:0", verbose=False )

这里有两个阈值要解释清楚。conf是置信度阈值,只有置信度大于这个值的目标才会被输出。调低conf可以降低漏检,但也会引入更多误检;调高conf则相反。产线场景我通常建议0.3到0.4之间。iou是NMS(非极大值抑制)阈值,它控制两个重叠框是否被合并,默认0.45对PCB缺陷来说比较合适。如果同一缺陷被重复框出多个框,可以把iou调高到0.5以上,合并得更干净。

遍历结果的代码也很简单:

for result in results: boxes = result.boxes for box in boxes: x1, y1, x2, y2 = box.xyxy[0].tolist() conf = float(box.conf[0]) cls = int(box.cls[0]) label = f"{result.names[cls]} {conf:.2f}"

拿到每个框的坐标、置信度和类别后,就可以用OpenCV把框画到图像上,同时在左上角标出缺陷类别和置信度数字。这里我的经验是:不同缺陷类别用不同颜色的框,比如短路用红色、开路用橙色、鼠咬用黄色,这样质检员在界面上扫一眼就能快速分清优先级。

5.3 效果演示与性能实测数据

实际跑测试集的效果,我用一组数据来说明。在一张包含多个缺陷的复杂板卡图上,模型在640分辨率下输出6个检测框,其中有5个是真缺陷,1个是多余的铜箔误检,置信度从0.42到0.93不等。开路的置信度最高,因为断口特征明显;伪铜的置信度偏低,因为它的视觉特征和正常铜面更接近。

性能方面,单张图片在NVIDIA GPU上的推理时间大约是10毫秒,加上前后处理和绘制框,总耗时在15毫秒左右,折算下来每秒可以处理60多帧。这个速度对于静态检测已经绰绰有余,对产线实时检测也基本达标,除非是特别高速的轨道相机才需要进一步用TensorRT做INT8优化。

6. 常见问题与排查技巧实录

6.1 训练阶段的典型问题

训练时最容易遇到的是显存不足。我处理方法是先降batch size到8,再开梯度累积,等效于仍然用16的batch训练,只是显存占用减半。如果还爆显存,就把输入分辨率降到512,但代价是小目标检测精度会下降。还有一个容易被忽略的技巧:训练时关闭图像缓存到内存的功能,某些情况下GPU显存占用会明显下降。

数据集格式错误是另一个高频问题。YOLO训练对数据路径和标注格式要求严格,最常见的报错是图片和标签对不上、图片加载失败。每张图像必须有对应的TXT文件,即使该图像没有任何目标,也要有一个空的TXT文件,否则训练过程中会跳过该图像,导致数据损失。我在数据准备脚本里加了检查逻辑,统计每个类别在每个文件中的标注数量,有问题会在开始训练前就暴露出来。

6.2 检测效果不佳的调试方向

模型训练完了,mAP也好看,但实际检测时漏检严重,这个问题通常出在三个地方。

第一是输入分布差异太大。数据集里的图像和你现场拍的照片在光照、分辨率、板卡颜色上差异明显,模型没见过这种分布,自然检不出来。解决办法是尽量在现场采集图片补充训练,哪怕只有一两百张,效果提升都会非常显著。

第二是置信度阈值设得太高。默认0.25在看起来不错,但PCB缺陷这种低对比度目标,实际推理的置信度普遍偏低,我建议先降到0.1看看能检出多少目标,再逐步提高找到一个平衡点。

第三是推理分辨率。如果你的现场图像是4K的,而训练用的是640,直接把原图喂进去,小目标会被压没。正确做法是用切图推理或缩放推理加多尺度测试增强,把大图切成若干小块分别检测,再合并结果。

6.3 部署阶段的实战经验

部署时最容易被卡住的是环境依赖。PyTorch、CUDA、TensorRT的版本必须互相兼容,我踩过最大的坑是CUDA版本和PyTorch预编译包不匹配,运行时报"CUDA driver version is insufficient",排查了半天才发现是环境问题。建议严格按照requirements.txt和官方环境配置文档来搭环境,不要图省事直接用pip默认装最新版。

另一个实战经验是模型更新迭代的机制。产线上跑一段时间后,会积累新的缺陷样本,可以定期把这些样本加入训练集,重新训练一个新版本权重,然后通过配置文件切换模型,不需要改任何界面或推理代码。我在这套项目里预留了这个接口,config.yaml里改一下模型路径就能切换,极大简化了维护工作。

我在实际使用这套系统时最大的体会是:训练模型的时间可能只占全项目三分之一,真正花时间的是数据清洗、GUI打磨和现场适配。YOLO26给了我们一个性能很好的起点,但要让它在自己的产线上稳定运行,还需要把数据闭环跑起来——收集漏检样本、定期补充标注、重训模型、验证效果,形成一个持续优化的正向循环。

最后分享一个小技巧:如果你在部署现场调试时发现某些缺陷类型的漏检率特别高,先别急着动模型参数,去现场多拍一些这类缺陷的照片,加入数据集训练一轮。多数情况下的效果提升,比调任何参数都来得明显。这套项目的所有代码和数据流程都是围绕这种迭代优化的思路设计的,希望它能帮你省去起步阶段的大量摸索时间。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 9:40:14

YOLO11-C3k2-RVB:PCB缺陷检测实战改造与部署全解析

在PCBA产线上跟缺陷检测打交道久了的工程师都有一个体会:模型在论文数据集上拿高分是一回事,能稳定扛住产线的光照抖动、板面脏污和不同批次板卡的色差是另一回事。我去年用YOLO11-C3k2-RVB这个改进结构替掉原来产线上的检测模型,最大的触动不…

作者头像 李华
网站建设 2026/10/19 9:40:11

毕业设计实战:爬虫、舆情分析与可视化一站式打通

毕业设计怎么把“爬虫、舆情分析、可视化”三个坑一次填平每年到这个时候,总有一批人要做“基于大数据的社交平台数据爬虫舆情分析可视化系统”这类毕业设计。我想说的是,这个题目看上去是三个词拼一起,实际上它是一个完整的数据工程链路——…

作者头像 李华
网站建设 2026/10/19 9:39:30

STM32驱动ADS1220高精度ADC:从寄存器配置到多通道低功耗采集

简介:这份ADS1220驱动代码面向使用STM32F407进行嵌入式开发的工程师与学习者,针对24位高精度ADC在传感器接口、医疗设备及精密测量等场景下的驱动实现问题,提供可直接参考的底层代码方案。资源包共2个文件,包含1个ads1220.h头文件…

作者头像 李华
网站建设 2026/10/19 9:38:50

无感FOC零速低速段怎么控?脉振高频注入法原理与实战

第一次给板子写完无感FOC固件,我按下启动键,电机在零速附近“嗡”了一下,然后开始不紧不慢地反向爬行,电流波形像心电图一样乱跳——那一刻我就知道,转子位置估计在零点附近栽了跟头。做永磁同步电机(PMSM&…

作者头像 李华
网站建设 2026/10/19 9:37:42

iFlow CLI hook实战:Windows下打造个性化任务完成通知

开头最近我一直在用一个叫 iFlow 的任务管理工具,日常把它挂在命令行里,随手抓任务、写待办。用得多了就开始不满足于它默认那套提醒方式:任务完成的时候,屏幕上顶多弹个系统通知,消息内容固定,也没有任务详…

作者头像 李华
网站建设 2026/10/19 9:37:25

环境管理方案:Shell脚本与Docker Compose如何选择与配合

这两年我经手维护的项目里,环境管理方案出现了很明显的分化:老一点的仓库还靠一串 Shell 脚本打天下,新一点的项目基本都切到了 Docker Compose。两种方案我都在实际项目里深度用过,也分别踩过不少坑。今天不站队说谁一定更好&…

作者头像 李华