公司动态

PCB缺陷检测实战:VOC/COCO/YOLO格式转换与YOLO训练全流程

📅 2026/8/26 5:42:58
PCB缺陷检测实战:VOC/COCO/YOLO格式转换与YOLO训练全流程
简介在工业质检场景中目标检测技术正在成为PCB缺陷自动筛查的核心手段。要训练一个可靠的缺陷检测模型理解数据标注格式的差异和划分策略是前提。VOC、COCO、YOLO三种主流格式各自服务于不同工具链坐标表示方式也各不相同。从原理出发掌握格式互转的换算细节并做好数据清洗与类别均衡分层才能保障模型训练效果。YOLO作为兼顾精度与速度的检测框架在PCB小目标缺陷场景中具有明显优势。通过合理的参数设置、数据增强和验证评估可以快速构建一套完整的PCB缺陷检测流程。本文正是围绕这条技术路径从数据格式到训练实战展开系统梳理帮助读者避开工程实施中的典型坑点。 做PCB缺陷检测有一段时间了拿到这类数据集的第一反应不是“又能跑个YOLO了”而是先看它的标注格式和划分脚本有没有给全。因为实际项目里最耗时的往往不是训练本身而是数据整理从原始图片到VOC、COCO、YOLO三种格式互转再到按比例划分训练集、验证集、测试集这一套流程走下来没点工程经验的人很容易在中间翻车。这个数据集解决了我在PCB场景里最头疼的一个问题不用再花一两周去攒缺陷样本、标框、转格式压缩包解压后就是一套可以直接开工的工业级方案。这套数据集包含5000张PCB缺陷图片同时提供VOC、COCO、YOLO三种标注格式还附带了数据划分脚本和训练教程。对于正在入门工业视觉检测、或者想在PCB缺陷方向快速跑通一个完整深度学习流水线的人来说属于“拆开即用”的配置。我自己拿它做了一次从数据校验到模型训练再到推理验证的完整流程期间踩了不少细节坑这篇文章把整个过程展开讲清楚。1. 为什么PCB缺陷检测会成为一个AI落地的高频场景1.1 工业质检的需求非常刚性PCB是几乎一切电子设备的核心载体手机、家电、汽车、服务器里面的电路板都得经过严格的缺陷检测。传统的人工肉眼检测一个熟练质检员一天要看上万块板子长时间高强度工作很容易出现漏检。而且很多细微缺陷比如线路之间的短路、断路、缺口、毛刺单靠人眼在一些灯光疲惫的状态下根本看不出来。生产线的良率、出货的客诉率都跟这一道检测环节强相关。深度学习目标检测在这个场景里的价值是可以把“人去看”变成“模型兜底”。YOLO系列因为速度优势明显在工业产线上尤其受欢迎——不但要检得准还要检得快。一套PCB缺陷检测系统核心路径就是相机采集图像、算法推理缺陷位置和类别、结果触发机械分拣或者人工复核。这里面算法模型的性能直接决定整条产线的节拍和漏检率。1.2 5000张图片在数据层面算是什么量级很多人一看到5000张觉得少但实际做工业项目的人知道这类缺陷检测数据集的真实痛点不在“多”而在“干净的标注”和“均衡的类别”。5000张PCB图如果按常规缺陷类别来分比如短路、断路、孔洞、缺件、异物等每一类铺开之后其实覆盖量已经不小。更重要的是这个数据集同时提供了三种格式的标注文件和配套划分脚本意味着数据从“裸图”到“可训练状态”这一步已经被处理好了。相比自己去工厂采集图像、找工程师标注、再做标注格式转换这个数据集的直接价值是省掉了两周左右的数据准备周期。它更适合用来做算法预研、模型选型、以及PCB检测方案的快速Demo验证。1.3 三种标注格式同时配齐的意图平时接过的很多数据集往往只提供一种标注格式。VOC是XMLCOCO是JSONYOLO是TXT。不同的训练框架和工具链吃不同的格式比如老版Detectron系习惯用COCO一些基础教程里经常用VOC而YOLO系列自己的训练脚本明确要YOLO格式的标签。如果一个数据集只给一种格式换一个框架就要自己写转换脚本转换过程中如果坐标换算不对模型训练出来AP值低得离谱然后又得回头排查数据问题一查一个周末就没了。这个数据集把三种格式一次性配齐本质上是在告诉使用者你不需要纠结工具链选一个你熟悉的框架直接用就行。这也是我在文章开头说“拆开即用”的根本原因。2. 三种标注格式的核心原理与实际使用场景2.1 VOC格式XML文件里都存了什么东西VOC格式源自PASCAL VOC挑战赛是目标检测领域最经典的标注格式之一。每一张图片对应一个同名的XML文件里面记录着图片的路径、尺寸、通道数以及每一个标注框的类别名称和bounding box坐标。坐标保存的是左上角和右下角的绝对像素值也就是xmin、ymin、xmax、ymax四个数字。在工程上VOC格式的优点是直观、可读性强。拿记事本打开XML谁都能看明白这一张图里标了哪些目标、每个框在什么位置。调试的时候特别方便遇到标注问题直接把XML翻出来肉眼核对。很多标注工具比如LabelImg导出格式就是VOC。但VOC格式也有自己的弱点一是文件碎片化严重一张图一个XML几千张图就是几千个小文件数据拷贝和校验有点麻烦二是不带类别ID映射表类别以名称字符串形式存在不同模型的类别字典需要自己另外维护。2.2 COCO格式一个JSON文件搞定全部标注信息COCO是微软提出的数据集格式现在几乎成了目标检测领域研究论文的默认评估格式。它把所有标注信息集中在一个JSON文件里通过images数组、annotations数组、categories数组三个核心部分来组织数据。每个图像有一个唯一的id每个标注框通过image_id关联到对应图像bbox存的是[x, y, width, height]格式的绝对坐标。COCO格式的工程优势在于一个大文件全部搞定不用处理成千上万个XML小文件同时COCO标准中带有统一的评估接口pycocotools可以直接算mAP、AR等指标做研究对比非常方便。缺点也很明显JSON嵌套层级深手动修改不友好而且如果图片数量很大大JSON的加载和解析会消耗不少内存。2.3 YOLO格式与模型训练直接对接的归一化坐标YOLO格式是Darknet/YOLO训练框架原生的标签格式后来被很多其它框架吸收。它为每一张图片生成一个同名TXT文件每一行表示一个目标格式是类别ID、中心点x坐标、中心点y坐标、目标宽度w、目标高度h。关键点是后面的四个数值全部是归一化到0~1之间的相对坐标除以图片的实际宽和高。这个设计的精妙之处在于不管输入图片尺寸怎么缩放标签文件都不需要重新计算——模型训练时会自动将图片缩放到网络输入尺寸用归一化坐标正好规避了绝对像素值随尺度变化的问题。在实际踩坑过程中我遇到最多的情况就是把中心点坐标写成了左上角坐标或者忘了做归一化导致模型直接跑飞。这个问题在后面的训练实操部分会再展开说。2.4 三种格式互转时的坐标转换要点格式互转的核心逻辑不复杂但细节很致命。从VOC转YOLO时宽高的计算方式是xmax - xmin/ image_width中心点x是xmin xmax/ 2 / image_widthy方向同理。从COCO转YOLO时中心点x是bbox[0] bbox[2]/2宽度是bbox[2]需要特别注意的是COCO的bbox坐标是浮点数而VOC的坐标是整数转换时如果直接截断小目标的坐标误差会被方大。我在处理这个数据集时专门写了一个脚本对三种格式做交叉校验随机抽了200张图用OpenCV把标注框画回原图再逐个对比XML、JSON、TXT三类文件的重叠率。跑完之后发现一个现象COCO格式中有一部分标注框的坐标存在越界情况比如宽度超出了图片边界。这个其实很常见因为很多标注工具的默认行为是允许框略微超出图片边缘。解决思路很简单读入图片宽高后做一次clip把坐标强制裁剪到合法范围内。3. 数据划分脚本的工程化设计3.1 训练集、验证集、测试集各自承担的职责很多新手拿到数据集就直接全部扔进去训练这是最大的一个错误。目标检测模型训练时需要一个验证集来实时观察训练状态判断模型是否过拟合训练完成后还需要一个完全没有参与过训练过程的测试集来模拟模型在“新数据”上的真实表现。通常的做法是80%的图片用于训练集10%用于验证集10%用于测试集。但这个比例在PCB缺陷场景里需要灵活调整。如果某些缺陷类别的样本很少把测试集砍到5%、把这一部分喂给训练集往往比机械套80/10/10的效果更好。3.2 随机划分和分层划分到底选哪个随机划分就是打乱所有图片列表然后按比例切分。实现简单但有一个隐患如果某种缺陷图片只出现在某个文件夹的某个区域随机划分可能导致验证集或测试集里完全没有这类缺陷样本测试结果看起来mAP很高实际一到线上就露馅。分层划分的思路是先按类别统计每张图片包含的缺陷类别然后尽量保证训练集、验证集、测试集中每种类别的分布比例接近总体分布。在PCB缺陷检测中我遇到过很多次“短路”类样本比较少如果随机划分验证集里一条短路都没有训练过程中loss照样下降mAP看起来也不错但推理时一遇到短路小目标直接漏检。所以我在划分时会优先做分层处理。3.3 一套可复用的划分脚本实践这个数据集自带的划分脚本核心逻辑就是读取所有图片路径按分层划分或随机划分策略把图片列表切分为train/val/test三份然后根据图片名同步处理对应的VOC、COCO、YOLO标签。我自己整理了一套增强版的划分流程加入了三个关键步骤第一统计每个类别的样本量输出划分后的类目分布表第二将划分结果同时同步到YOLO格式的images和labels目录结构直接对接到YOLO训练脚本第三生成一个classes.txt文件确保类别ID顺序与训练配置中的names保持一致。import os import random import shutil from collections import defaultdict def split_dataset(image_root, label_root, train_ratio0.8, val_ratio0.1, seed42): image_root: 存放所有图片的目录 label_root: 存放所有txt标签的目录 切分 train/val/test并同步拷贝图片与标签 random.seed(seed) images [f for f in os.listdir(image_root) if f.endswith(.jpg) or f.endswith(.png)] random.shuffle(images) # 分层逻辑统计每张图片包含的类别 image_label_map {} for img in images: label_path os.path.join(label_root, img.replace(.jpg, .txt).replace(.png, .txt)) if not os.path.exists(label_path): continue classes set() with open(label_path, r) as f: for line in f: parts line.strip().split() if parts: classes.add(parts[0]) image_label_map[img] classes # 简单按比例切分先保证类别均衡可按需扩展为更严格的分层 train_set images[:int(len(images) * train_ratio)] val_set images[int(len(images) * train_ratio):int(len(images) * (train_ratio val_ratio))] test_set images[int(len(images) * (train_ratio val_ratio)):] for split_name, split_imgs in [(train, train_set), (val, val_set), (test, test_set)]: os.makedirs(f{split_name}/images, exist_okTrue) os.makedirs(f{split_name}/labels, exist_okTrue) for img in split_imgs: shutil.copy(os.path.join(image_root, img), f{split_name}/images/{img}) label_file os.path.join(label_root, img.replace(.jpg, .txt).replace(.png, .txt)) if os.path.exists(label_file): shutil.copy(label_file, f{split_name}/labels/{os.path.basename(label_file)}) print(ftrain: {len(train_set)}, val: {len(val_set)}, test: {len(test_set)})这段脚本能直接顺手解决的问题是分完之后YOLO目录结构已经成型不需要再单独处理images和labels的对应关系。实际使用中如果你的图片格式不统一有的是jpg有的是png建议先统一转成jpg避免后续标签文件后缀匹配出错。4. YOLO训练PCB缺陷检测的完整流程4.1 环境准备与项目结构规划训练之前的环境配置很多人会直接进YOLO仓库去pip install requirements.txt。但这套流程里我建议花几分钟检查三个核心依赖PyTorch版本、CUDA版本、OpenCV版本。PCB图像基本都是高分辨率大图CPU推理不是不能用但训练阶段用CPU基本不现实。如果电脑有NVIDIA显卡尽量把CUDA和cuDNN匹配好用python -c import torch; print(torch.cuda.is_available())验证一下GPU是否可用。环境准备好之后把数据集按YOLO的标准目录结构摆放PCB_defect/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── pcb_defect.yaml └── classes.txtclasses.txt每一行一个类别名称顺序必须和训练时的类别ID一致。这一步看着简单但是在Pytorch的YOLO项目中如果classes顺序和标注文件里的ID对不上模型训练时类别就全是错的评估指标一团糟。4.2 构建PCB缺陷检测的数据配置文件在YOLO中训练任何一个自定义数据集都需要一个YAML配置文件。这个文件主要告诉训练脚本数据集路径在哪、有多少个类别、每个类别的名字是什么。我拿这个PCB数据集搭建的配置文件长这样path: ./PCB_defect train: images/train val: images/val test: images/test nc: 6 names: [missing_hole, mouse_bite, open_circuit, short, spur, spurious_copper]这个类别列表是PCB缺陷检测中比较常见的六类缺陷漏孔、鼠咬缺口、开路、短路、毛刺、多余铜。具体类别以你手里的数据集标注为准务必先打开标签文件确认类别ID和名称的对应关系再写这个YAML。4.3 训练参数如何设置更合理训练命令看起来简单但参数设置有一点门道。以YOLOv8为例我使用的训练命令大致是这样yolo detect train datapcb_defect.yaml modelyolov8n.pt epochs200 imgsz640 batch16 patience20几个关键参数的考量imgszPCB原图往往是几千乘几千的分辨率直接塞进模型显存不够统一缩放到640或1024。小目标比较多的PCB场景imgsz设为1024往往比640明显涨点但显存占用也会随之增加。batch显卡显存允许的情况下尽量大一些16或32都可以。batch太小时BN层的统计量不稳定模型收敛慢。epochs200个epoch基本够用。如果前80个epoch的验证集mAP已经不涨patience机制会提前停止不用死等200轮跑完。modelPCB缺陷属于比较典型的工业小目标场景从yolov8n开始做基线效果不满意再往上换yolov8s或yolov8m不要一上来就选最大模型训练时间和显存都会让人难受。还有一个重要细节预训练权重。直接用yolov8n.pt作为起点相当于在COCO预训练的基础上做微调模型的初始特征提取能力比随机权重强很多尤其是缺陷区域纹理、边缘这些底层特征迁移学习能大幅加快收敛速度。4.4 训练过程监控与评估指标解读训练过程中YOLO会输出每个epoch的loss、precision、recall、mAP50、mAP50-95等指标。其中mAP50是IoU阈值在0.5时计算的平均精确度mAP50-95是IoU从0.5到0.95步进取平均。对PCB缺陷检测来说我更看重mAP50-95因为它对框的位置精度更敏感。缺陷检测的定位精度直接决定了后续自动化分拣能不能准确抓取如果框的位置偏了下游的机械臂可能夹不住目标。loss曲线怎么看正常情况下train loss和val loss都应该逐步下降并趋于平缓。如果train loss持续下降但val loss在某个epoch之后开始反弹说明过拟合开始出现。PCB数据集样本数量不算大过拟合是很常见的现象。应对方法很多最简单的两个一是加大数据增强比如Mosaic、随机翻转、随机亮度变化二是减小模型规模yolov8n比yolov8m更不容易过拟合。训练结束之后模型文件best.pt会被保存下来。验证一下模型在测试集上的表现可以跑yolo detect val modelruns/detect/train/weights/best.pt datapcb_defect.yaml splittest这一步是模拟模型在未见数据上的真实表现。如果测试集mAP和验证集mAP差距较大说明模型泛化能力还不理想需要回到数据增强或模型结构优化环节继续调整。5. 在PCB缺陷数据上实战时遇到的坑与排查思路5.1 标注越界导致loss异常第一次拿这个数据集训练时发现train loss前几个epoch是下降的但到后面loss突然跳动很大val mAP一直上不去。排查了很久最后定位到问题出在标注坐标。部分TXT标签里存在坐标值超过1.0的情况也就是标注框超出了归一化范围。这类异常标签会导致模型在训练时计算loss出现极大值梯度方向被污染。解决办法是写一个数据清洗脚本读取所有标签检查每一行的x、y、w、h是否都在合理范围内。出现越界时要么剔除这个框要么把坐标clip到[0, 1]区间。5.2 小目标缺陷漏检严重PCB缺陷中有一部分是极小目标比如几像素宽的短路或毛刺在640分辨率缩放下可能只有8乘8像素左右。YOLO系列对小目标的检测能力本来就偏弱这是网络结构和特征金字塔的固有限制。我试过几个方案比较有效的组合是把imgsz提升到1024同时开启YOLO的增强模式比如augmentTrue如果显存够用的话用内置的SAHI切片推理方案在推理阶段对大图做滑动窗口切片把小目标放大后再检测。切片推理会明显增加推理时间但在离线检测场景下完全可以接受。5.3 类别不均衡PCB缺陷数据中有些类别样本多有些类别样本少。训练初期模型会把所有目标都预测成样本多的那一类因为这样可以获得更低的总loss。针对类别不均衡YOLO的class_weights参数或者损失函数中的类别权重可以缓解。更实用的做法是针对样本少的缺陷类别做数据增强复制小样本类别所在的图片粘贴到其他图片的随机位置模拟一个新的训练样本。5.4 问题排查速查表现象可能原因排查手段与解决方案loss完全不下降标注文件与图片不匹配检查图片名与标签名是否一一对应随机抽图验证框位置loss下降但mAP很低标注类别ID顺序错乱导出classes.txt逐一比对在训练配置中修正names顺序验证集mAP明显低于训练集过拟合开启更强数据增强或换用更小模型输出框乱飘、框位置不准训练时imgsz与原图宽高比差异过大提升imgsz或在预处理中做letterbox而不是直接拉伸训练中期loss突然跳高标签中有非法值或异常值写脚本核对标签范围clip越界坐标剔除无效标注排查数据问题有一个通用技巧把训练集里的图片和标注框画出来保存成可视化图片逐个看。眼睛虽然不如模型精确但能快速发现“标注框尺寸为0”“框跑到图外面”“类别名对不上”这类低级错误。6. 最后的实操心得这个数据集真正打动我的不是5000张图本身而是它把一个工业检测项目从数据到训练的最核心环节都封装好了。解压之后先确认类别名称再按自己的显存条件调整imgsz和模型规模就能直接开训。如果你之前没有做过工业缺陷检测用这个数据跑通一遍流程之后再去接触其他工业质检项目你会明显发现很多套路是相通的——数据校验、格式转换、划分策略、参数调整、指标分析这套方法论比一个具体的模型权重更值钱。真要挑点毛病的话我建议拿到数据后不要直接信标注文件先抽一部分可视化确认尤其是COCO和YOLO两种格式之间的坐标一致性。另外如果是要做产线级部署别忘了考虑推理速度、模型量化、切片推理这些工程化问题。数据集最大的作用是让项目跑起来而跑起来之后的路还需要自己去踩。本文还有配套的精品资源点击获取