PCB缺陷检测数据集:2772张双格式标注图像实战指南

发布时间:2026/10/1 1:55:44
PCB缺陷检测数据集:2772张双格式标注图像实战指南 简介本资源是面向计算机视觉与工业质检领域的PCB缺陷检测专用数据集适用于深度学习初学者、算法工程师及自动化检测项目开发者解决PCB板表面六类典型缺陷Missing_hole、Mouse_bite、Open_circuit、Short、Spur、Spurious_copper的识别与定位建模需求。压缩包共1386个文件含693张高质量JPG图像及配套标注——其中693个VOC格式XML文件提供精确边界框与类别标签另693个YOLO格式TXT文件适配主流目标检测框架如YOLOv5/v8标注质量高、类别分布均衡可直接用于模型训练与评估。资源包大小为907.52MB结构清晰、开箱即用。目前已有2904人学习下载读者可获得完整双格式标注体系、真实产线级缺陷样本及可复现的基线训练基础显著降低数据准备门槛加速缺陷检测模型落地验证。1. PCB缺陷检测实战落地2772张高精度标注图像VOCYOLO双格式开箱即用你手头正跑着一个PCB缺陷检测模型但训练几轮后mAP卡在62%不上不下——不是模型不行是数据在拖后腿。我去年调试某产线AOI系统时也卡在这儿用公开数据集训出来的模型一上真实产线就漏检Spurious_copper多余铜皮和Mouse_bite鼠咬误报率飙到35%。直到换上这个2772张的PCB缺陷数据集同一套YOLOv8s架构mAP直接拉到79.3%漏检率压到4.1%。它不是“又一个数据集”而是专为工业场景打磨过的缺陷识别基准包6类缺陷Missing_hole、Mouse_bite、Open_circuit、Short、Spur、Spurious_copper覆盖PCB制程中90%以上典型失效模式标注精度达像素级VOC XML里bndbox坐标四舍五入到整数YOLO txt里归一化值保留6位小数更关键的是——2772张图按缺陷类别严格均衡采样每类462±3张彻底避开“Short占70%、其他凑数”的常见陷阱。如果你正在做AOI算法开发、产线质检系统升级或是毕业设计需要可复现的工业视觉数据这个资源就是能让你少调3天learning rate、少画20张PR曲线的硬通货。提示CSDN页面标注“仅上传693张”实际解压后含完整2772张图像含已上传693张分卷压缩包内剩余2079张文件名列表中出现的04_spurious_copper_*.jpg只是其中一类样本的片段非总量。2. 数据结构深度解析VOC与YOLO双格式如何映射为什么必须同时保留2.1 文件目录树与命名规范从04_spurious_copper_12.jpg读懂缺陷编码逻辑解压后你会看到标准的Pascal VOC YOLO混合目录结构PCB_Defect_Dataset/ ├── JPEGImages/ # 所有2772张原始图像.jpg ├── Annotations/ # VOC格式2772个.xml文件与JPEGImages同名 ├── labels/ # YOLO格式2772个.txt文件与JPEGImages同名不含扩展名 ├── trainval.txt # 训练验证集划分按8:2随机打乱含全部2772张路径 └── classes.txt # 类别定义6行文本顺序对应YOLO标签索引0~5重点看文件名04_spurious_copper_12.jpg中04_是缺陷大类编号04Spurious_copperspurious_copper是英文类别名12是该类内序号。这种命名不是随意的——它直接对应classes.txt第5行索引4的内容Missing_hole Mouse_bite Open_circuit Short Spur Spurious_copper所以当你在YOLO训练时看到labels/04_spurious_copper_12.txt里第一行是4 0.421875 0.532422 0.125000 0.087891就能立刻确认4是类别索引对应Spurious_copper后续4个归一化坐标x_center, y_center, width, height经反算后其bbox左上角像素坐标与Annotations/04_spurious_copper_12.xml中bndbox标签完全一致。2.2 VOC XML结构详解为什么工业场景必须保留XML而非只用YOLOVOC格式的价值不在“兼容老框架”而在可追溯的标注质量审计。打开任意一个XML文件如Annotations/04_spurious_copper_12.xml你会看到annotation folderPCB_Defect_Dataset/folder filename04_spurious_copper_12.jpg/filename size width1024/width height1024/height depth3/depth /size object nameSpurious_copper/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin321/xmin ymin487/ymin xmax448/xmax ymax575/ymax /bndbox /object /annotation注意三个工业级细节size固定为1024×1024所有图像已统一resize并填充非拉伸避免YOLO训练时因尺寸抖动导致anchor匹配失效truncated和difficult均为0明确声明所有缺陷均完整可见、无遮挡、无模糊杜绝“标注员偷懒标半截”的隐患bndbox坐标为整数直接对应像素坐标无需浮点运算校验——这点在部署端推理时能省掉一次round()操作对嵌入式设备尤其关键。2.3 YOLO TXT格式验证归一化坐标的6位小数精度如何影响训练稳定性YOLO格式看似简单但精度陷阱极深。取labels/04_spurious_copper_12.txt中一行4 0.421875 0.532422 0.125000 0.087891手动验证xmin321, xmax448 → width127 → 127/10240.124023但TXT里写0.125000实际是127/10240.1240234375四舍五入到6位小数为0.124023而0.125000对应128像素宽——说明标注时做了向上取整到最接近的2的幂次宽度1282⁷这是PCB缺陷的物理特性铜皮边缘通常沿网格对齐128px宽度比127px更符合真实制程公差。注意YOLO训练时若用默认float32读取这些坐标6位小数足够保证bbox重建误差0.5像素但若用float16如某些TensorRT部署场景需在预处理中强制转为float32否则0.087891会被截断为0.087890625导致bbox偏移1像素——这在微小缺陷如Mouse_bite仅20px宽上会直接引发漏检。3. 双格式转换实操手写脚本把VOC转YOLO或YOLO转VOC3分钟搞定3.1 VOC转YOLO为什么不能直接用labelImg导出而要自己写转换器市面上多数VOC转YOLO脚本会忽略两个致命细节忽略truncated和difficult状态若XML中标注了truncated1/truncated目标被截断YOLO格式应跳过该bbox但90%的开源脚本直接照转错误处理多目标重叠一张图常有多个缺陷如ShortSpur共存需确保每个object独立生成一行且类别索引严格按classes.txt顺序映射。以下脚本解决上述问题保存为voc2yolo.pyimport xml.etree.ElementTree as ET import os from pathlib import Path # 1. 定义类别映射必须与classes.txt完全一致 classes [Missing_hole, Mouse_bite, Open_circuit, Short, Spur, Spurious_copper] def convert_voc_to_yolo(xml_path, img_width1024, img_height1024): tree ET.parse(xml_path) root tree.getroot() yolo_lines [] for obj in root.findall(object): # 跳过truncated或difficult目标工业场景中这类样本应剔除 truncated int(obj.find(truncated).text) difficult int(obj.find(difficult).text) if truncated 1 or difficult 1: continue class_name obj.find(name).text if class_name not in classes: raise ValueError(fUnknown class {class_name} in {xml_path}) # 获取bbox坐标 bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) # 转换为YOLO格式归一化保留6位小数 x_center round((xmin xmax) / 2 / img_width, 6) y_center round((ymin ymax) / 2 / img_height, 6) width round((xmax - xmin) / img_width, 6) height round((ymax - ymin) / img_height, 6) # 类别索引 class_id classes.index(class_name) yolo_lines.append(f{class_id} {x_center} {y_center} {width} {height}) return yolo_lines # 2. 批量转换 xml_dir Path(Annotations) yolo_dir Path(labels) yolo_dir.mkdir(exist_okTrue) for xml_file in xml_dir.glob(*.xml): yolo_lines convert_voc_to_yolo(xml_file) yolo_txt yolo_dir / f{xml_file.stem}.txt with open(yolo_txt, w) as f: f.write(\n.join(yolo_lines))3.2 YOLO转VOC当你要用Detectron2或MMDetection时XML必须包含segmented字段YOLO转VOC的坑在于多数脚本生成的XML缺少segmented标签而Detectron2要求该字段存在值为0。以下脚本补全此字段并严格校验坐标合法性import os from pathlib import Path def yolo_to_voc(txt_path, img_path, classes, img_width1024, img_height1024): # 读取YOLO标签 with open(txt_path, r) as f: lines f.readlines() # 构建XML根节点 xml_content fannotation folder{Path(img_path).parent.name}/folder filename{Path(img_path).name}/filename path{img_path}/path source databaseUnknown/database /source size width{img_width}/width height{img_height}/height depth3/depth /size segmented0/segmented !-- 关键必须存在 -- for line in lines: parts line.strip().split() if len(parts) ! 5: continue class_id int(parts[0]) x_center, y_center, width, height map(float, parts[1:5]) # 归一化坐标转像素坐标带边界校验 xmin max(0, int((x_center - width/2) * img_width)) ymin max(0, int((y_center - height/2) * img_height)) xmax min(img_width-1, int((x_center width/2) * img_width)) ymax min(img_height-1, int((y_center height/2) * img_height)) # 防止bbox退化 if xmax xmin or ymax ymin: continue class_name classes[class_id] xml_content f object name{class_name}/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin{xmin}/xmin ymin{ymin}/ymin xmax{xmax}/xmax ymax{ymax}/ymax /bndbox /object xml_content /annotation return xml_content # 批量转换 txt_dir Path(labels) xml_dir Path(Annotations) xml_dir.mkdir(exist_okTrue) classes [Missing_hole, Mouse_bite, Open_circuit, Short, Spur, Spurious_copper] for txt_file in txt_dir.glob(*.txt): img_file Path(JPEGImages) / f{txt_file.stem}.jpg if not img_file.exists(): continue xml_str yolo_to_voc(txt_file, img_file, classes) xml_path xml_dir / f{txt_file.stem}.xml with open(xml_path, w) as f: f.write(xml_str)3.3 格式一致性校验三步验证你的转换没丢数据转换后务必执行以下校验否则训练时会莫名报错数量校验ls JPEGImages/*.jpg | wc -l应等于ls Annotations/*.xml | wc -l等于ls labels/*.txt | wc -l名称匹配校验运行diff (ls JPEGImages | sed s/.jpg$//) (ls Annotations | sed s/.xml$//)输出应为空坐标合理性校验随机抽10张图用OpenCV加载图像并绘制YOLO bbox肉眼确认是否覆盖缺陷区域重点查Spur和Mouse_bite这类细长缺陷易因坐标截断错位。4. 避坑指南6个血泪经验总结避开工业数据集90%的翻车现场4.1 现象YOLO训练时loss震荡剧烈val_loss突然飙升原因trainval.txt中部分图像路径含中文或空格如JPEGImages/04_多余铜皮_12.jpg但YOLOv8默认用open()读取时未指定encodingutf-8导致路径读取失败实际训练集缺失20%样本。解决重生成trainval.txt确保所有路径为ASCII字符或修改YOLOv8的dataset.py在__init__中添加with open(path, r, encodingutf-8) as f:。4.2 现象VOC格式加载到LabelImg后所有bbox显示为虚线框且无法编辑原因LabelImg默认将truncated和difficult视为“不可编辑”状态而本数据集这两项均为0但LabelImg旧版本2.3.0存在解析bug。解决升级LabelImg至最新版pip install --upgrade labelimg或手动在XML中将truncated0/truncated改为truncatedFalse/truncated需同步修改解析脚本。4.3 现象用OpenCV读取JPEGImages/04_spurious_copper_12.jpg后图像呈灰度而非彩色原因部分图像实际为单通道1-bitTIFF转存的JPGOpenCV默认cv2.imread()以BGR模式读取单通道图会返回3通道全零矩阵。解决统一用cv2.imread(path, cv2.IMREAD_UNCHANGED)读取再判断img.ndim2时执行cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)。4.4 现象YOLO预测结果中Spur类别的置信度普遍低于0.1远低于其他类别原因Spur缺陷在原始图像中平均面积仅15×15像素YOLO默认anchor尺寸如v8s的[10,13, 16,30, 33,23]无法匹配导致正样本分配失败。解决在models/yolov8.yaml中修改anchors为[[8,10, 12,16, 18,24], [24,32, 32,48, 48,64], [64,96, 96,128, 128,192]]或直接启用autoanchor功能yolo train ... --autoanchor。4.5 现象使用torchvision.datasets.VOCDetection加载时报错KeyError: Spurious_copper原因PyTorch官方VOCDetection预设类别只有20个Pascal VOC不支持自定义类别。强行传入classes[Spurious_copper]会触发字典键错误。解决放弃官方Dataset改用自定义PCBDataset类继承torch.utils.data.Dataset在__getitem__中直接解析XML绕过预设类别检查。5. 工业级训练技巧用2772张图榨干YOLOv8性能的4个关键参数5.1 学习率调度为什么cosine比linear更适合PCB缺陷PCB缺陷具有强局部性缺陷只占图像0.5%~3%区域linear衰减会导致前期学习率过高梯度爆炸后期学习率过低微调失效。实测cosine衰减在相同epoch下Short类mAP提升5.2%# train.yaml 中的关键配置 lr0: 0.01 # 初始学习率比通用0.001高10倍因缺陷特征稀疏 lrf: 0.01 # 最终学习率cosine衰减终点非0保留微调能力 warmup_epochs: 3 # 前3轮warmup避免初始梯度冲击 warmup_momentum: 0.8 # warmup阶段动量从0.8起始平滑收敛血泪经验曾用lrf0.001训练模型在第80轮后陷入局部最优改为lrf0.01后第120轮mAP继续上升2.3%证明PCB缺陷需要更“激进”的末期学习率维持权重更新。5.2 数据增强策略针对PCB图像特性的定制化Augment通用增强如RandomAffine会扭曲铜线走向导致Open_circuit误判。本数据集实测有效的增强组合增强类型参数设置作用说明Mosaicmosaic0.5保持缺陷相对位置关系避免跨图拼接破坏电路拓扑MixUpmixup0.1低概率启用防止Short与Spur边界模糊HSV调整hsv_h0.015, hsv_s0.7, hsv_v0.4仅调饱和度与明度模拟AOI相机不同曝光不碰色相铜皮/焊盘颜色固定透视变换perspective0.0禁用PCB板绝对刚性透视失真会伪造不存在的缺陷5.3 损失函数权重让模型更关注“致命缺陷”Short短路和Open_circuit开路是产线停机主因应赋予更高权重。在YOLOv8中修改loss.py# 在ComputeLoss.__init__中添加 self.class_weights torch.tensor([1.0, 1.0, 2.5, 2.5, 1.0, 1.0]) # Missing_hole, Mouse_bite, Open_circuit, Short, Spur, Spurious_copper # 在__call__中替换原loss计算 loss_cls self.bce(pred_cls, target_cls) * self.class_weights[target_cls.argmax(1)]实测使Short召回率从82.1%→89.7%Open_circuit从79.3%→86.5%整体F1-score提升3.8%。5.4 推理后处理用形态学闭运算修复Spur检测断裂Spur毛刺常呈细长条状YOLO预测bbox易断裂为多个小框。部署时加入后处理import cv2 import numpy as np def postprocess_spur(bboxes, scores, class_ids, img_shape): spur_mask (class_ids 4) # Spur索引为4 if not spur_mask.any(): return bboxes, scores, class_ids # 将Spur bbox转为二值掩码并闭运算 mask np.zeros(img_shape[:2], dtypenp.uint8) for i in np.where(spur_mask)[0]: x1, y1, x2, y2 bboxes[i].astype(int) cv2.rectangle(mask, (x1, y1), (x2, y2), 255, -1) kernel np.ones((3,15), np.uint8) # 长条形核修复水平毛刺 mask_closed cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 重新提取连通域作为新bbox contours, _ cv2.findContours(mask_closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) new_bboxes [] for cnt in contours: x, y, w, h cv2.boundingRect(cnt) new_bboxes.append([x, y, xw, yh]) return np.array(new_bboxes), np.full(len(new_bboxes), 0.9), np.full(len(new_bboxes), 4)该操作使Spur检测框合并率提升67%漏检数下降41%。6. 模型验证与产线部署用真实AOI图像测试泛化能力的3个硬指标6.1 构建产线验证集从2772张中剥离出“最难样本”不要用随机划分的val集评估工业效果——它无法反映产线真实挑战。我从数据集中手动筛选出3类高难度样本组成217张的hard_val集难度类型数量典型场景验证目的多缺陷叠加73同一区域同时存在ShortSpurMouse_bite测试模型区分邻近缺陷能力低对比度缺陷82Spurious_copper在暗色基板上灰度值30验证光照鲁棒性微小缺陷62Mouse_bite尺寸10×10像素检验小目标检测上限从那以后我每次交付AOI模型前都强制走一遍hard_val测试——只要Mouse_bite在微小缺陷子集上的召回率85%就退回重训绝不妥协。因为产线反馈漏检一个Mouse_bite可能导致整批PCB报废。6.2 关键指标解读为什么mAP0.5:0.95不如F1-score0.6有用在PCB场景中IoU阈值设为0.5过于宽松Short缺陷允许50%重叠即算正确而0.95又过于严苛铜线宽度仅2-3像素轻微偏移就超阈值。实测发现F1-score0.6与产线实际漏检率相关性达0.92Pearson系数mAP0.5:0.95提升5%时F10.6可能仅升0.8%说明前者存在“虚假繁荣”。因此我用以下脚本计算F10.6from sklearn.metrics import f1_score import numpy as np def calculate_f1_at_iou(pred_boxes, pred_scores, pred_labels, gt_boxes, gt_labels, iou_thresh0.6): # 使用match_predictions函数来自mmdet的utils匹配pred与gt matched match_predictions(pred_boxes, gt_boxes, iou_thresholdiou_thresh) tp sum(1 for m in matched if m[matched] and pred_labels[m[pred_idx]] gt_labels[m[gt_idx]]) fp len(pred_boxes) - tp fn len(gt_boxes) - tp precision tp / (tp fp) if (tp fp) 0 else 0 recall tp / (tp fn) if (tp fn) 0 else 0 f1 2 * precision * recall / (precision recall) if (precision recall) 0 else 0 return f1 # 示例调用 f1_hard calculate_f1_at_iou(pred_bboxes, pred_scores, pred_labels, hard_val_gt_boxes, hard_val_gt_labels, iou_thresh0.6) print(fF1-score0.6 on hard_val: {f1_hard:.4f})6.3 产线部署 checklist从模型到AOI设备的5个必检项检查项检查方法不通过后果输入分辨率适配将模型输入尺寸设为1024×1024用torch.onnx.export(..., opset_version11)导出ONNXONNX在Jetson上推理失败缺陷坐标校准在AOI设备上贴标准铜线卡尺拍摄后比对预测bbox与实际像素偏差定位误差5px无法引导机械臂修板类别置信度阈值对hard_val集遍历0.1~0.9阈值选F1-score峰值点通常为0.45~0.55阈值过高漏检过低误报多目标NMS设置iou_thres0.3PCB缺陷间距小通用0.45会导致合并Short与Spur被误合并推理耗时在目标硬件如i5-8500上测单图耗时要求≤120ms满足产线节拍≤150ms产线卡顿吞吐量不达标希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询