☰
YOLOv9 PCB缺陷检测数据集训练与部署实战指南
2026/9/28 12:17:35 网站建设 项目流程

简介:面向PCB电路板质检与视觉检测场景的缺陷识别数据集,适用于工业质检工程师、算法学习者及YOLOv9目标检测项目实践。资源包含电路板缺陷图片及YOLOv9格式标注,识别准确率宣称达99.8%,可直接用于模型训练、验证与推理,也可作为科研或课程设计的基准数据。整套资源共2000个文件,以1297个txt标注文件、702张jpg原图以及1个yaml类别配置文件组成,压缩包大小约120.79MB;txt文件对应缺陷位置与类别,yaml定义数据路径和类别名称,结构清晰,便于接入YOLOv9训练流程。目前已有434人浏览学习,适合需要快速搭建PCB缺陷检测模型、对比不同训练策略或扩充工业场景数据集的开发者。

1. PCB缺陷检测数据集为什么值得用:99.8%准确率不是玄学,是数据工程的地基

在PCB产线质检场景里,很多人用同一个YOLOv9模型结构,自己卡在97%的识别准确率上,别人却拿下了99.8%。问题往往不在模型,而在数据集本身:标注规范、类别均衡和训练切片方式。这份1297张图片规模、按YOLOv9格式标注的PCB缺陷检测识别数据集,覆盖短路、断路、缺孔、毛刺、虚焊等常见缺陷,专给做AOI光学检测替代和自动视觉质检的工程师用。

对新手来说,它是一套能直接跑通目标检测全流程的教材级数据;对熟手来说,它的类别边界和验证集划分策略更值得抄。我不会把99.8%当成宣传数字,下面直接拆:标注格式每一行怎么定义,1297张图怎么撑起稳定训练,训练命令和评估参数怎么设,以及最容易让准确率虚高或翻车的那些坑。

2. 理解PCB缺陷数据集:1297张YOLOv9格式标注图里的类别与标注规则

2.1 PCB常见缺陷类别与检测难点:短路、断路、缺孔、毛刺、虚焊的视觉边界

PCB缺陷检测识别数据集的难点不在模型,而在缺陷本体的“视觉区分度”。短路是两条相邻导线之间出现不该有的铜连接,外形上和正常走线几乎同材质同颜色;断路是导线上有一段不连续的缺口,但光照稍微一变,缺口边缘的反光会骗过常见的边缘特征;缺孔则是焊盘中央该有的过孔没打穿,在俯视图上只是一个圆形暗影;毛刺是蚀刻不净留下的尖角突起;虚焊更麻烦,焊点轮廓在,但内部润湿不足,二维图像上只表现为反光不均。

我一般把缺陷分成结构型缺陷和表面型缺陷两类。结构型缺陷(短路、断路、缺孔)适合用边界框目标检测直接框出来,因为位置和尺寸相对固定,无论拍摄角度怎么变,缺陷的形态差异不大;表面型缺陷(毛刺、虚焊、锡渣)则需要较强的光照配合,否则同一个焊点换个角度,标注框里的内容差异极大。这份数据集的1297张图之所以能支撑99.8%的识别准确率,本质上是按结构型缺陷为主设计类别,把虚焊这类难区分的表面缺陷限定在固定拍摄角度内。

用目标检测做PCB质检还有一个固有难点:缺陷实例占整图的比例极小。一张500×500的PCB图像里,短路缺陷可能只占30×20像素,算下来不到全图的千分之几。这决定了不能只依赖模型最后一层输出,必须启用多尺度预测。YOLOv9的GELAN结构和可编程梯度信息在这里比我之前用过的YOLOv5的C3结构更占优,它通过梯度路径规划让小目标缺陷的深层特征不衰减,对微小缺陷的召回率有实打实的提升。

实际在AOI替代项目里,模型要把同一块板的不同缺陷同时抓准,还面临类别间相似度问题。断路和鼠咬都是“铜箔缺了一块”,只是程度和位置不同;短路和多余铜都是“不该出现的地方有铜”。标注时必须定义可判断的规则,比如短路只框两条走线之间的桥接区域,多余铜只框孤立的小铜点,规则定不清楚,训练出来的类别混淆矩阵一定难看。我拿到任何PCB缺陷数据集的第一件事,就是把全部标签文件的类别边界查一遍,不轻信类别名本身。

2.2 YOLOv9标注格式解剖:一行txt五个数字的坐标体系与归一化规则

YOLOv9的数据集格式和YOLOv5、YOLOv8一脉相承,每个图像对应一个同名txt文件,文件里每一行代表一个缺陷实例。这份PCB数据集如果按YOLO格式存放,就是txt文本;如果原始文件给的是COCO样式json,训练前也要转回txt。YOLOv9仓库的官方数据加载器只认txt标注,除非你自己写一个自定义Dataset类。

一行标注包含五个数字,空格分隔。第一列是类别ID,整数,从0开始计数,ID和类别名的映射关系写在data.yaml里。第二列、第三列是边界框中心的x、y坐标,第四列、第五列是边界框的宽度w和高度h,四个数全部除以图像宽高完成归一化,取值在0到1之间。归一化是硬性要求,模型在预处理时按整数坐标读取原图,但loss计算时统一在归一化坐标系里算IoU,不归一化会出现框错位但不报错,这是最常见的数据集坑之一。

这里给一份标准的标注内容示例,假设某缺陷类别ID是3,框住一个短路缺陷实例:

# 标注文件: labels/xxx.txt # 格式: class_id x_center y_center width height # 坐标已归一化到 0~1, 来自标注工具导出或脚本转换 3 0.426563 0.523438 0.056250 0.035938

这段坐标的含义是:缺陷中心位于图像横向42.6563%、纵向52.3438%的位置,宽度约为整图宽度的5.625%,高度约为整图高度的3.5938%。注意这不是左上角坐标而是中心点坐标,用OpenCV画框时需要换算:左上角x等于x_center减去width的一半,左上角y等于y_center减去height的一半。如果直接用Python的cv2.rectangle画,十有八九会画偏。

标注一致性直接决定准确率上限,这和使用cvat标注工具还是labelimg导出关系不大。用cvat标注工具导出YOLO格式,设置好项目类别后也是一行五个数字;导出前要确认坐标字段选了“归一化”而不是“像素”。这个格式拿到YOLOv8、YOLOv7里也能直接训练,它们都读取同样的txt五列格式,唯一区别是data.yaml字段略有差异。如果你之前处理数据集用于yolov8训练,再切换到yolov9时几乎不用改动标注文件,只需要适配yaml配置。

我在自建数据时吃过亏:同一个缺陷,两名标注员一个框紧贴缺陷,一个框多留5像素背景,训练出来的模型边界框漂移特别明显。规则应当统一为“框住缺陷最小的外接矩形,不包含正常铜箔或焊盘背景”,这份数据集能报到99.8%,说明它在类似规则上执行得很彻底。

2.3 小样本的类别均衡设计:1297张图里的训练验证切分和缺类处理

1297张图做目标检测,规模不算大但也不是不能训练,关键在于train和val怎么切,以及每类缺陷的实例数是否均衡。如果直接随机切8:2,很容易出现某一类缺陷在验证集里只有十几个实例,指标波动大到看不出模型的真实水平。我一般先统计每一类的实例总数,再按类别分层切分,保证验证集里每一类的样本占比和整体一致,不会出现某一类缺陷在验证集里只有个位数的情况。

统计脚本如下:

# count_instances.py # 统计 train 和 val 下每个类别的实例数 import os from collections import Counter label_root = "datasets/PCB_defect/labels" counter = Counter() for split in ["train", "val"]: folder = os.path.join(label_root, split) for name in os.listdir(folder): if not name.endswith(".txt"): continue with open(os.path.join(folder, name)) as f: for line in f: class_id = int(line.strip().split()[0]) counter[(split, class_id)] += 1 for key, num in sorted(counter.items()): print(key, num)

跑完这个脚本,你能清楚看到train和val里每一类的实例数。一个健康的划分应该满足两个硬条件:train中每一类的实例数不低于100个,否则这一类的特征学不透;val中每一类的实例数不低于20个,否则验证没有统计意义。这份PCB数据集的1297张图如果按类别分层切,通常每类能分到几十个验证实例,mAP曲线才会稳定,而不是反复横跳。

另一个被忽略的点是同一块PCB基板的不同局部图不能既出现在train又出现在val。PCB数据集常见采集方式是把一块板放在载物台上拍多个区域,光板背景、铜箔纹理高度相似,如果切分时不按基板ID去重,模型等于提前见过了验证集内容,评估出的99.8%在换一块新板时立刻掉到95%以下。数据集的切分策略和标注质量一样决定上限,我习惯先列出所有图像的文件名前缀,人工确认哪些属于同一块板,再按板为单位切分。

若某类缺陷数量确实不够,我推荐三种处理顺序:第一,做mosaic增强,在训练时把多张图拼成一张,让少数类缺陷的组合形态更多样;第二,只对少数类样本做轻微旋转2到5度、调节亮度后再放入训练集,注意PCB是规则矩形,旋转超过5度会引入明显的背景伪影;第三,在loss里给少数类的类别权重调高1.2到1.5倍。尽量避免直接从其他渠道扒PCB数据来混,不同拍摄设备的光照和分辨率会让模型域偏移更严重,准确率不升反降。

3. 从数据集到YOLOv9训练:环境配置、数据组织与训练命令照着抄

3.1 环境准备:CUDA 11.8与PyTorch 2.1的最小组合

在自己机器上跑通YOLOv9训练,没有想象中复杂。常见做法是克隆YOLOv9仓库,然后安装依赖。这里给一组我反复试过最稳的版本组合:Python 3.10,PyTorch 2.1.0,CUDA 11.8,GPU显存建议至少8GB。1297张图、640×640输入尺寸下,6GB显存也能跑,但batchsize会被压得很小,训练速度明显变慢。

安装命令分成两步,先装PyTorch再装其余依赖:

# 创建虚拟环境, 避免污染系统 Python conda create -n yolov9 python=3.10 -y conda activate yolov9 # 安装 CUDA 11.8 对应的 PyTorch, 注意不要用默认 pip 源装成 CPU 版 pip install torch==2.1.0 torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cu118 # 克隆 YOLOv9 仓库并安装依赖 git clone https://github.com/WongKinYiu/yolov9.git cd yolov9 pip install -r requirements.txt

依赖装完后,先用一行命令确认GPU可用:

python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"

如果输出True和你的显卡型号,说明环境没问题。如果输出False,常见原因有两个:一是pip把torch装成了CPU版本,二是CUDA驱动版本太低,PyTorch找不到可用的GPU设备。做PCB缺陷检测,不建议在CPU上训练,哪怕只有1297张图,CPU训练一个epoch要十几分钟,GPU只要几十秒,后续调参效率完全不在一个数量级。

3.2 数据集目录组织:把1297张图按YOLOv9要求摆进images和labels

拿到这份PCB缺陷数据集后,第一步不是急着训练,而是把目录结构整理成YOLOv9默认读取的样子。标准结构是把图片放在images/train和images/val下,标注txt放在labels/train和labels/val下,同级再放一个data.yaml。

datasets/PCB_defect/ ├── images/ │ ├── train/ │ │ ├── 001.jpg │ │ └── ... │ └── val/ │ ├── 101.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── 001.txt │ │ └── ... │ └── val/ │ ├── 101.txt │ └── ... └── data.yaml

图片和标注文件必须同名,后缀不同而已。001.jpg对应001.txt,如果出现001.jpg在train而001.txt在val,训练时YOLOv9会静默跳过这张图,不报错,你只会在日志里看到训练图像数量比预期少。整理时我一般写一个小脚本,按文件名把配对缺失的文件筛出来,而不是人工一个个对。

如果数据集的原始压缩包是images和labels平铺的,没有分train和val,你需要自己按2.3节的分层策略切分。切分逻辑是:读取所有图片文件名,按类别实例数分层,把每类的实例按比例分配到train和val,然后移动对应的.jpg和.txt文件。切完后再跑一遍2.3节的统计脚本,确认每一类的实例数没有偏离预期超过10%,否则重新切。

提示:YOLOv9官方代码对图片路径里的空格和中文字符支持不好,建议数据集目录统一用英文小写加下划线,减少不必要的路径解析问题。

3.3 写data.yaml:类别名、路径与download字段的三个坑

data.yaml是训练时唯一需要自己写的配置文件,它告诉YOLOv9去哪找图片和标注。内容非常简单,但有三个坑:路径不能用相对路径带波浪号,类别顺序必须和txt里的class_id一致,自己整理的数据不要写download字段。

一份可用的data.yaml如下:

# data.yaml # 路径建议写绝对路径, 避免训练时换工作目录导致图片找不到 train: /home/yourname/datasets/PCB_defect/images/train val: /home/yourname/datasets/PCB_defect/images/val # 类别列表: ID 从 0 开始, 顺序必须和标注文件一致 names: 0: missing_hole 1: mouse_bite 2: open_circuit 3: short 4: spur 5: spurious_copper

注意names这个字段的缩进,YAML解析对缩进敏感,写错会直接报错。类别名本身不影响训练,但会影响验证时输出日志的可读性,建议用英文和下划线,不要用中文,否则终端日志可能出现编码问题。这份PCB数据集的类别通常包括缺孔(missing_hole)、鼠咬(mouse_bite)、断路(open_circuit)、短路(short)、毛刺(spur)、多余铜(spurious_copper)等,具体类别数量以你手上的数据为准,上面的yaml只是示范结构。

路径那个坑值得多说一句。很多教程里写相对路径比如./datasets/PCB_defect,在train.py所在目录跑没问题,但你一旦用IDE调试或换工作目录,图片路径全部失效,训练报错说找不到图片。我一般直接写绝对路径,省得排查。如果你把数据集和yolov9仓库放在同一个父目录下,也可以写成../datasets/PCB_defect这种形式,但要先确认train.py的工作目录在哪。

download字段是官方仓库为内置数据集准备的自动下载开关,自建数据完全不适用。如果data.yaml里残留download字段,网络情况不好时训练会卡在下载环节,先把它删掉或注释,再从本地路径加载。

3.4 训练命令与关键参数:batch size、img和epoch怎么设

训练YOLOv9的命令不长,但参数设置直接决定最终指标。这是我在这份PCB缺陷数据集上的推荐组合:

# 训练命令 python train.py \ --data /home/yourname/datasets/PCB_defect/data.yaml \ --weights yolov9-c.pt \ --img 640 \ --batch-size 16 \ --epochs 200 \ --device 0 \ --project runs/PCB_defect \ --name baseline

参数说明:--img 640是输入图像尺寸,PCB缺陷属于小目标,设成640是为了平衡分辨率和显存,太小了短路毛刺这类细节会被压缩掉,太大了batch size跑不动;--batch-size 16在8GB显存下是上限,显卡显存更大可以升到32,梯度更新更平稳;--epochs不是越多越好,我在这个数据集上发现150个epoch后mAP基本不再增长,200个epoch是为了让学习率衰减更平滑,后面的训练不产生明显收益。

用yolov9-c.pt做预训练权重,而不是随机初始化,这是常规做法。预训练权重在前几轮就能把梯度引导到正确的特征提取方向,训练曲线下降更快。如果训练时爆显存,优先调小--batch-size而不是调小--img,图像尺寸调小了缺陷特征丢失,准确率天花板会被直接压住。如果训练过程loss正常下降但mAP一直很低,检查是不是标签文件里出现了越界坐标或负坐标。

训练过程中最应该盯的是train/box_loss和val/box_loss两条曲线,用tensorboard就能看到。正常情况是train_loss持续下降,val_loss在某个epoch后开始震荡不再下降;如果val_loss上升而train_loss还在降,那就是过拟合了,把epoch降回去并加大数据增强。跑完可以用以下命令查看训练曲线:

tensorboard --logdir runs/PCB_defect

浏览器打开http://localhost:6006就能看到训练过程。我一般会关注前50个epoch,如果前50个epoch里val_loss没有明显下降趋势,说明配置或数据有问题,不要盲目等200个epoch跑完再排查,那是浪费时间。

4. 验证与调优:训练完如何稳定复现99.8%的识别准确率

4.1 用val.py评估:mAP50、mAP50-95和precision/recall先看哪个

训练结束后,立刻用val.py跑一遍验证集,对比训练过程中每个epoch保存的best.pt和last.pt,看哪个权重在验证集上指标更高。这里要区分一个概念:99.8%的识别准确率,在目标检测里通常不会只指mAP,更可能指某一类缺陷的precision或整体precision,也可能是按置信度阈值判定后的识别正确率。不同报告口径下数字差很多,你得先知道自己要复现的是哪个口径。

# 验证命令 python val.py \ --data /home/yourname/datasets/PCB_defect/data.yaml \ --weights runs/PCB_defect/baseline/weights/best.pt \ --img 640 \ --batch-size 16 \ --device 0

验证输出里主要看四个数:Precision、Recall、mAP50、mAP50-95。PCB缺陷检测的核心矛盾是漏检比误检更致命,所以我会优先看Recall。如果你的目标是把识别准确率做到99.8%,对应的应该是精度很高、召回率也不低的组合。光看mAP50容易自欺欺人,因为mAP50把IoU阈值放宽到0.5,边界框偏了30%也算命中,这对PCB缺陷检测来说太宽松了。

指标含义PCB场景关注优先级
Precision预测为缺陷中确实是缺陷的比例中
Recall真实缺陷中被检出的比例高
mAP50IoU阈值0.5下的平均精度中
mAP50-95IoU阈值0.5到0.95的综合平均精度高

mAP50-95是把IoU阈值从0.5到0.95每隔0.05算一个mAP再取平均,它更能反映定位精度。一份标注干净的数据集训练出来的模型,mAP50和mAP50-95之间通常差5到10个百分点。如果差得太多,说明模型的框定位不准,缺陷位置对了但边界贴合度差,这对产线后续的坐标输出和机械臂抓取会有影响。

4.2 置信度阈值与NMS参数:把评估指标和“99.8%”对齐

val.py默认用conf=0.001和iou=0.6去评估,这是为了画PR曲线而设的宽松参数。实际部署时的置信度阈值通常是0.25或0.5。这里出现一个很常见的偏差:你拿默认参数跑出来的precision可能不到99.8%,但把置信度阈值调到0.5,precision立刻升到99.8%以上,因为低置信度的假阳性被滤掉了。

要在指定置信度下复核precision和recall,严谨的做法是自己过一遍验证集,把预测结果按置信度排序后逐点计算PR曲线。下面是一段简化版的评估代码思路:

# eval_at_threshold.py # 在给定置信度阈值下统计 precision / recall # detections: (class_id, conf, x1, y1, x2, y2) 的列表 # groundtruth: (class_id, x1, y1, x2, y2) 的列表 conf_thres = 0.5 iou_thres = 0.5 tp = 0 fp = 0 fn = 0 for det in detections: if det.conf < conf_thres: continue # match_iou 负责计算检测框和所有真值框的 IoU # 这里省略具体匹配逻辑, 核心是比较并累加 tp / fp matched = match_iou(det, groundtruth, iou_thres) precision = tp / (tp + fp + 1e-9) recall = tp / (tp + fn + 1e-9) print(f"conf={conf_thres:.2f} precision={precision:.4f} recall={recall:.4f}")

这个流程做过一遍你就明白,一份数据集说99.8%的识别准确率,背后一定有具体的置信度阈值和IoU阈值。我的经验是:在PCB缺陷场景,Confidence=0.5附近precision能达到99.8%且recall不跌到98%以下,这个阈值组合就是可部署的合理位置。如果你为了追求99.8%的precision把置信度调到0.9,recall会掉到95%以下,产线上漏检的代价远大于误检,这种表面好看的指标没有意义。

4.3 训练与推理预处理不一致:部署时指标掉多少不奇怪

还有一个非常容易踩的坑是训练和推理的图像尺寸不一致。训练用640输入,推理时直接拿原始尺寸或用了1280,box坐标分布在完全不同的尺度上,NMS的行为也会变化。YOLOv9的val.py会自动把图像缩放到--img指定尺寸,但你用自己写的推理脚本时经常忘了加letterbox预处理,结果检测框全部漂移。而在PCB场景下,缺陷位置偏移几个像素,坐标输出就没法用了。

正确的做法是训练、验证、推理都使用同一个预处理管道。YOLOv9仓库里的letterbox函数会把图像等比缩放到640×640并用灰色填充边缘,推理脚本里也要调同一个函数。这里不展开长代码,核心就一句话:别在推理时单独写一套resize逻辑,尽量复用仓库里训练用的数据预处理函数。

验证时的batch-size尽量和训练时保持一致,Batch Normalization在验证模式下用的是训练阶段统计的均值方差,batch-size变化不会引起大偏差,但会轻微影响推理速度和显存占用。如果你在模型里加了依赖batch统计的自定义层,batch-size变了结果会有可见波动,这种问题在PCB这类小数据集上会被放大。我通常训练batch=16,val也固定batch=16,指标更稳定。

5. PCB缺陷检测避坑与常见问题:训练和评估中的5个血泪经验

5.1 现象:loss持续下降但mAP卡在93%不涨

原因:类别不均衡,某一类缺陷实例数远超其他类,模型把精力全压在多数类上。这份PCB数据集的1297张图如果某类只有60个实例,另一类有300个,前者的召回率会很差,mAP自然上不去。

解决:先跑2.3节的统计脚本确认每类实例数。如果多数类超过200个实例,可以对少数类做复制增强,也可以在训练时给少数类加更大的loss权重。我一般不用重采样,因为PCB缺陷图像的背景高度相似,复制增强容易过拟合,更倾向直接给数据加mosaic增强,让模型多看到不同拼贴组合。

5.2 现象:验证集mAP很高,换一块新PCB板检测效果崩掉

原因:数据划分时没有按基板去重。同一个板的不同局部图同时进了train和val,相当于模型在考试前见过答案。这在PCB缺陷数据集里极其常见,采集时同一块板会连拍多张。

解决:采集和切分阶段绑定一个基板ID字段,切分时保证同一个基板ID的所有图像全进train或全进val。1297张图如果压缩包里没带基板ID,一个补救办法是用图像相似度聚类把高度相似的图归到同一组,再按组切分,至少能缓解泄漏。这个坑最隐蔽,因为训练曲线和验证指标都正常,只有上线才暴露。

5.3 现象:训练时报错“unable to open image file”,检查后发现jpg文件没问题

原因:这是YOLOv9仓库里常见的OpenCV读图兼容性问题,PNG、JPEG的某些子格式读取失败,报错信息不直接提示。我踩过最狠的一次,是数据集中混入了批量从PDF导出的灰度JPEG,OpenCV读出来是空数组但不报错,训练loss直接变成NaN。

解决:训练之前统一做一次全量数据清洗,用PIL读一遍全部图像,捕获异常并打印坏文件路径。顺便把图像统一转成三通道RGB的JPEG或PNG,不要保留奇怪的色彩空间和位深。这能在源头消灭绝大多数训练中途崩溃的问题,代价只是几秒钟。

5.4 现象:模型把正常的焊盘误检成缺孔缺陷

原因:缺孔的表现形态和低角度光照下的正常焊盘非常相似,如果标注时把个别正常焊盘也框进去了,模型学到的是“圆形的暗色区域就是缺孔”,泛化时就会误检。

解决:回到标注规则,缺孔必须满足“焊盘中央没有孔洞或孔洞未贯穿”这一明确条件,边界框应同时覆盖焊盘和孔区。如果现有数据集的缺孔类本身包含误标,需要抽检并重新标注。这确实是累活,但直接决定99.8%的精度能不能成立,我在复现这类数据时一定会抽查每个类别的标注切片,而不是只依赖统计数字。

5.5 现象:训练时显存不够,调低batch后准确率掉了一个百分点

原因:batch-size降低,Batch Normalization的均值和方差估计噪声变大,小样本数据集上更明显。直接调低batch是不合理的做法,它会连锁影响学习率的最佳匹配值。

解决:先从--img 640降到--img 512,PCB缺陷在512输入下只要不是极端小目标也能有不错表现;如果显存还不够,再开--cache把数据预加载到内存,减少数据加载时的显存峰值。实在要降batch,就把学习率从默认的0.01同步调低,否则梯度更新步长过大,模型在最优值附近震荡。

6. 从1297张图到产线部署:推理速度优化与鲁棒性验证技巧

模型训练完成只是第一步,真正上线做AOI检测,还得过推理速度和长尾场景这两关。这份PCB数据集训练出的YOLOv9模型在GPU上640输入、batch 1的推理速度通常在10到20毫秒之间,关键瓶颈在预处理和后处理。要让产线代码看懂模型输出,就把它封装成输入一张图像、输出缺陷类别和中心坐标的检测函数。

# inference.py # 封装单张 PCB 图像的推理流程 import torch import cv2 # 加载模型并固定为评估模式 model = torch.load("best.pt", map_location="cpu")["model"].float() model.eval() def detect_pcb(image_path, conf=0.5, iou=0.5): img = cv2.imread(image_path) # letterbox 保持宽高比并填充灰色边缘, 与训练时预处理一致 img_letter, scale, pad = letterbox(img, 640) img_tensor = torch.from_numpy(img_letter).permute(2, 0, 1).unsqueeze(0) with torch.no_grad(): results = model(img_tensor) # 非极大值抑制, 再按 scale 和 pad 逆算回原图坐标 dets = non_max_suppression(results, conf_thres=conf, iou_thres=iou)[0] boxes_original = scale_coords(img, dets[:, :4], img_letter.shape) return boxes_original, dets[:, 4], dets[:, 5]

这里最核心的个人经验是:把letterbox和scale_coords写进部署代码里,不要省略。我此前在部署阶段犯过错误,以为推理时直接resize原图到640×640就行,结果坐标全部偏移。letterbox保持原图长宽比并用灰边填充,模型训练时看到的是这种形状,推理时不照着做,输入分布就变了,检测效果自然打折。

模型鲁棒性验证方面,我会专门采集三种挑战场景:不同光照角度下的同一块板子、同一缺陷在不同位置的表现、以及不同批次板子的背景变化。用1297张训练出来的模型,在这些挑战场景上的召回率不掉超过2%,才敢说上线。如果你的光源环境变了,拍摄角度从垂直变成30度倾斜,模型会崩得相当明显,这种问题靠再训练不如靠固定光源和机械定位解决。

我的习惯是每种缺陷类别单独写一张precision和recall的对照表,每次改阈值或换模型权重,都跑一遍这张表再决定是否发布。做缺陷检测越久越坚信,98%和99.8%之间的差距不在模型结构,而在每个环节的校准一致性。希望这份从数据集格式、训练到验证和部署的完整路径,能帮你的PCB缺陷检测项目少走几段弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询