
简介面向车身部件损坏与车体缺陷检测的VOCYOLO双格式数据集对应7825张车辆图像的缺陷标注涵盖划痕、凹陷、裂缝、破损、褪色等15类常见问题可直接用于YOLO系列、Faster R-CNN等目标检测模型的训练与评估服务汽车制造质检、自动驾驶感知、智能交通监控和保险定损等场景。压缩包共2000个文件以VOC格式xml标注文件为主1999个另含1个使用说明txt整体约655.83MBxml文件记录目标类别与边界框坐标txt文件提供归一化YOLO训练格式两类标注按图片编号一一对应便于直接接入数据加载器。已有813人学习下载。这套数据省去了从零采集和人工标注的繁琐过程适合有一定深度学习基础的研究者、算法工程师及汽车行业开发人员用于模型微调、精度对比或作为自有数据的补充训练集。1. 车身部件损坏车体缺陷检测数据集7825 张 VOCYOLO 双格式样本的开箱经验车身部件损坏车体缺陷检测数据集 VOCYOLO 格式 7825 张 15 类别 .7z是我最近做产线外观质检预研时用到的一份现成样本集。拿到手里先解压发现它不是简单的图片堆而是把 VOC 的 XML 和 YOLO 的 txt 两种标注都整合好省去了跨工具转换时最容易出错的坐标换算环节。整套数据覆盖车门、保险杠、翼子板等 15 类典型损伤分类细脏样本少适合从零快速训练一个能区分“划痕、凹陷、开裂”这类问题的检测模型。新手可以拿它跑通主流框架的完整流程熟手则可以直接把类别清单和目录结构套用到自己的质检项目里。下面我会按解压、训练、评估、避坑的顺序把值得注意的细节都过一遍。2. 15 类检测任务与双格式标注为什么这样才能少踩坐标换算的坑2.1 为什么会设计成 15 类缺陷粒度与维修决策挂钩做车身缺陷检测最怕两件事一是把“凹陷”和“划痕”混在一个框里二是把“保险杠破损”和“车门凹陷”这种不同维修方式的目标当成同一个类。这套数据集按“损坏类型 部件位置”的规则切成 15 类。我拿到手后核对了类别清单常见的是车门凹陷、翼子板变形、保险杠破损、后备箱盖凹陷、侧围划痕、引擎盖凹陷、车灯破裂、前挡风玻璃裂纹、车顶凹陷、立柱变形、踏板损坏、后视镜破损、轮毂刮伤、门槛变形、格栅损坏。每个类别的样本数量并不均等这是车身缺陷数据的常态。划痕和凹陷在真实事故里出现频率高样本会占大头踏板损坏、门槛变形这种小概率部位样本相对少。类别设计本身没问题但训练时要注意给少数类加权或者做针对性增强否则模型容易把少数类学成“背景”。这个粒度还有一个好处在模型推理完成后可以直接按类别编号映射到维修工单模板不用再在业务层做二次分类。2.2 VOC 与 YOLO 格式的差异坐标体系换算逻辑VOC 格式把每个目标写成 XML 节点使用 xmin、ymin、xmax、ymax 的绝对像素坐标YOLO 格式则使用归一化的中心点坐标和宽高。两者都是矩形框但换算方向相反。YOLO 训练时读 txt 标注很多标注工具导出的是 VOC 或 COCO不转换直接喂给 YOLO 框架框的位置就会全部错位。这套数据集同时给了两种标注但我在不少依赖预标注的落地项目里遇到的通常是只有其中一种。完整的转换脚本如下参数需要按图片宽高归一化import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_txt_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text xml_cls_id class_names.index(name) # class_names 是全局类别列表 bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h box_w (xmax - xmin) / img_w box_h (ymax - ymin) / img_h # 防止裁剪标注边界出现负值 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) box_w min(box_w, 1.0) box_h min(box_h, 1.0) lines.append(f{xml_cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) with open(out_txt_path, w, encodingutf-8) as f: f.write(\n.join(lines))脚本逻辑是从 XML 里读图片尺寸和目标框把左上角、右下角坐标转换成中心点加宽高的相对值。最容易被忽略的是类别编号必须与 class_names 的索引一致。如果 data.yaml 里按字母序排类别而转换脚本按业务顺序排就跑出来全是错位类别。建议 class_names 列表直接复用数据集自带的 labels.txt不要自己在脚本里重排。2.3 目录结构与 .7z 压缩解压前先看清这三层这份数据用的是 .7z 而非 zip。7z 在压缩率上有明显优势尤其是缺陷照片里噪声纹理多同质量下体积通常比 zip 小 30% 到 50%。但对工程化来说更重要的是目录结构。常见布局是images/train、images/val 放图片labels/train、labels/val 放对应的 YOLO txtAnnotations 目录保留原始 VOC XML再加上一个 classes.txt 或 label_list.txt 记录类别编号和名称。解压 .7z 时我一般会先检查是否有中文路径或超长路径尤其在 Windows 环境7z 对 Unicode 目录名偶尔会出现解压后文件名乱码。把压缩包复制到纯英文路径下再执行7z x dataset.7z -oc:\quality_data能减少很多莫名奇妙的“标签对不上图”问题。解压后不要立刻训练先跑一遍目录校验每张图必须对应一个同名的 txtXML 里的图片名与 images 目录下的文件名一致。这套数据集已经内置核对好的双格式但从命令行手动解压后第一件事仍然是核对数量和文件名。3. 从 7z 到跑通 YOLOv5一份可直接照做的训练流水线3.1 解压与目录校验别让图片和标签分家先确认下载完的压缩包大小和校验值再解压。命令行方式如下7z x 车身部件损坏车体缺陷检测数据集VOCYOLO格式7825张15类别.7z -oc:\defect_data cd c:\defect_data find . -type f -name *.jpg | wc -l find . -type f -name *.txt | wc -l第一个find统计图片数量第二个统计 txt 数量。7825 张图对应 7825 个 txt如果数量不一致需要检查解压是否中断。同一张图片在 images 和 labels 下必须有同名文件。我习惯再用一段脚本做严格对照for img in images/train/*.jpg; do name$(basename $img .jpg) if [ ! -f labels/train/$name.txt ]; then echo missing label: $name fi done这段命令只做一件事遍历训练集图片名检查 labels 下有没有同名 txt。缺失的 txt 会导致 YOLO 训练时抛Image has no labels告警或把整张图跳过。真正踩坑的时候往往不是整批丢失而是个别文件名因为大小写不一致找不上。数据集里如果是 .JPG 后缀脚本里写 .jpg 就会漏检所以我一般会用ls images/train | head -10先看实际后缀再编写循环。3.2 训练集与验证集划分按场景隔离而不是随机打散7825 张图不是全量训练需要划分出一部分做验证。如果随机打散容易把同一辆车的连续帧同时分进训练集和验证集导致验证分数虚高。缺陷检测里更稳的做法是先在文件名上做分组再把每个组整体划到一边。import os import random from collections import defaultdict random.seed(2025) image_dir images/train_full label_dir labels/train_full all_images [f for f in os.listdir(image_dir) if f.endswith((.jpg, .jpeg, .png))] # 按文件名前 8 位作为车辆 ID假设同一辆车连续拍摄 car_groups defaultdict(list) for img in all_images: car_id img[:8] car_groups[car_id].append(img) val_cars set(random.sample(list(car_groups.keys()), int(len(car_groups) * 0.2))) val_images [] train_images [] for car_id, imgs in car_groups.items(): if car_id in val_cars: val_images imgs else: train_images imgs print(ftrain: {len(train_images)}, val: {len(val_images)})脚本的关键参数是car_id img[:8]它假设文件名前 8 位能代表同一拍摄对象。如果文件名本身不含车辆 ID可以改为按时间戳前缀分组。这个 20% 的验证比例适合缺陷检测如果样本少可以下调到 15%。重点在于分组让验证集更接近真实场景否则模型在“背题”而不是在“学会”。3.3 配置 YOLOv5 data.yaml类别顺序必须和 txt 编号一致YOLOv5 的 data.yaml 是训练入口。类别顺序直接决定模型输出的含义。这份数据集如果自带 classes.txtdata.yaml 里直接引用即可train: c:/defect_data/images/train val: c:/defect_data/images/val nc: 15 names: 0: door_dent 1: fender_deform 2: bumper_damage 3: trunk_dent 4: side_scrape 5: hood_dent 6: headlight_break 7: windshield_crack 8: roof_dent 9: pillar_deform 10: pedal_damage 11: mirror_break 12: wheel_hub_scrape 13: threshold_deform 14: grille_damage写 data.yaml 时要注意两点。第一train和val给的是图片目录而不是标签目录YOLO 会默认在图片同级的 labels 目录下寻找标注。第二names 顺序必须和训练文本中的第一个数字一致。如果数据集自带的 classes.txt 顺序是 door_dent 在第一位并且 txt 里对应 0data.yaml 就不要按字母序重排。我见过有人为了看着整齐把 names 按字母排列结果所有类别标签全部错位训练 loss 看起来没问题验证 mAP 却一直上不去。3.4 启动训练参数设置与日志盯梢用 YOLOv5 训练标准启动命令如下python train.py \ --data data.yaml \ --weights yolov5s.pt \ --epochs 80 \ --batch-size 16 \ --img 640 \ --patience 10参数说明--weights yolov5s.pt使用 COCO 预训练权重做迁移学习比从头训练收敛快很多--epochs 80对 7825 张图来说够用了缺陷检测不需要像大规模分类那样跑 300 轮--batch-size 16要配合显存调整如果是 8G 显存就降到 8否则容易 OOM--patience 10是早停参数验证 mAP 连续 10 轮不升就自动停止。启动后不要只盯着 loss 下降还要注意每轮打印出的box_loss、obj_loss、cls_loss。比较关键的是 obj_loss如果它一直不降说明很多缺陷目标被当成了背景。训练结束后会生成 weights/best.pt 和 last.pt评估阶段使用 best.pt。4. 避坑拆这 7825 张数据时最容易翻车的五个点4.1 解压后 XML 里图片名和实际文件名对不上现象训练脚本报不了错但数据可视化时发现部分框画到了完全错误的图上。 原因打包工具把 XML 中的 filename 字段写成了相对路径有的带子目录前缀有的只有纯文件名而我用 basename 去匹配。 解决出现这种情况后不要手动改 XML。写脚本统一按图片实际文件名重写 XML 的 filename 字段然后重新生成 YOLO txt。做法是把 image 目录遍历结果作为唯一事实来源再解析 XML 里 object 的 box 坐标组合成新标注。4.2 labels 路径照抄导致训练集全部“找不到标签”现象训练启动后终端打出大量WARNING: No labels found in xxx并且正常运行到结束但 mAP 全为 0。 原因YOLO 在训练时不会报错退出只是静默跳过无标签图片。常见原因是 data.yaml 里 train 指向了 image 目录但 images 下的图片与 labels 下的 txt 不是并列关系而是 labels 被放进了另一个根目录。 解决把 labels/train 和 images/train 放在同一级主目录下确保images/xxx.jpg对应labels/xxx.txt。我一般先跑一条python -c import yolov5之后再用 YOLO 自带的datasets.py里的img2label_paths函数做路径映射看是否有不存在的标签。4.3 类别样本不均导致验证集上少数类 AP 为 0现象总 mAP0.5 能到 0.78但踏板损坏、门槛变形这两个类别在验证集上 AP 一直为 0。 原因这两个类别在数据集中占比太少随机划分后验证集里只分到几张而且这几张可能还是小目标模型根本没见到足够正样本。 解决划分数据集时做分层采样按类别分别保证验证集中每类至少 20 张。具体做法是把所有包含该类别目标的图片单独抽出再从剩余图片里补足其他样本。如果数量实在不够则考虑对少数类图片做裁剪增强复制出多个包含目标框的局部图再放进训练集。4.4 训练 loss 出现周期性跳变最终模型框偏大现象loss 曲线整体下降但每隔 5 个 epoch 出现一个尖峰验证框普遍比真实缺陷区域大一圈。 原因数据集中存在一批来自不同采集设备的图片分辨率差距过大模型在 640 输入尺寸下反复适应不同尺度分布。部分图片是整车身远景缺陷只占几十像素另一部分图片是近距离特写缺陷占半个图。 解决先按图片宽高做分层把靠近某一分辨率的图片单独统计。训练时采用 mosaic 增强和多尺度训练YOLOv5 里设置--multi-scale让模型在 480 到 640 之间动态切换输入尺寸。实践下来框偏大的情况会缓解但无法完全消除。更彻底的做法是对长边超过 1600 的图片先压缩到 1280 以内再做标注保持缺陷尺度的一致性。4.5 验证集划分忽略了同辆车的侧门与车尾图现象验证 mAP 很高但部署到现场后对新车同一部位的漏检率明显偏高。 原因随机划分时数据集中同一辆车的连续帧图片被同时分进训练集和验证集模型实际记住了这辆车的纹理和光照而不是缺陷的通用特征。 解决在划分阶段不能只看文件类别还要看文件名是否来自同一采集批次。按文件名前 8 位分组划分每组整体进入训练或验证。这个方法不能做到百分百防泄漏但对连续拍摄的缺陷图库是性价比最高的方案。5. 评估 15 类缺陷模型看哪些指标、抓哪些坏例5.1 指标选择mAP 不是唯一答案每类 AP 才是重点YOLOv5 训练结束后会输出results.csv包含 P、R、mAP0.5、mAP0.5:0.95。车身缺陷检测场景里我优先看 mAP0.5因为缺陷框不需要像目标检测竞赛那样精确到像素级。mAP0.5:0.95 是 IoU 从 0.5 到 0.95 取平均对框的精确位置更敏感适合评估缺陷定位是否足够准。两个指标都要看但业务决策主要交给 mAP0.5。分类别统计 AP 才是发现问题的手段。YOLOv5 本身保存了confusion_matrix.png和results.png但更直接的方法是跑一段验证脚本逐类输出数量与 APimport torch import pandas as pd model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt) results model.val(datadata.yaml, batch_size8) df pd.DataFrame(results.mp, indexresults.names).T df.columns [precision, recall, mAP_0.5, mAP_0.5_0.95] print(df.sort_values(mAP_0.5, ascendingTrue))这段脚本加载训练好的 best.pt在验证集上重新评估并把每个类别四个指标打印出来。参数说明model.val内部会读取 data.yaml 里的 val 路径batch_size越小越省显存但越慢。我通常把结果按 mAP 升序排序先看尾部那几个类别。如果某类 mAP 明明很高但推理时总漏检多半是验证集划分偏向容易样本而不是模型真的变好了。5.2 坏例分析从 predict 输出里挑出误检与漏检指标不能告诉你模型在哪里翻车只能告诉你它翻车了。我会用一段脚本把验证集预测结果保存成图python detect.py \ --weights best.pt \ --source c:/defect_data/images/val \ --save-txt --save-conf \ --conf-thres 0.25 \ --iou-thres 0.45--save-txt会为每张图保存一个 txt 文件格式是class conf x_center y_center w h--save-conf把置信度也写进去。把这些 txt 和 ground truth 做逐框匹配找出两类典型坏例一是 IoU 大于 0.1 但小于 0.5 的框说明模型“找到了目标但框不准”二是置信度高于 0.8 却完全没有和标注匹配的框说明模型学到了某种错误特征。这类坏例很有代表性车身侧面划痕和阴影的边缘纹理相似模型经常把排气管阴影当成侧围划痕。处理方式不是简单调高 conf-thres而是检查数据集中是否缺少“阴影干扰”类负样本。如果数据集里没有明确负样本目录可以从验证集中把误检图挑出来作为背景图加进训练集并保留原图所有正样本标注。5.3 混淆矩阵重点看类别对之间的互相干扰YOLOv5 训练完成后会生成confusion_matrix.png。在 15 类的矩阵里我只看主对角线两侧的高亮区域。最容易出现的干扰模式是“车门凹陷”和“侧围划痕”互相混同一个框里既有凹陷又有划痕标注人员只勾了其中一个类别模型学到的边缘特征有重叠。处理混淆对的方法是做标签复核把这两类类别组合产生的所有预测框导出逐个看它们是应该合并还是拆分。更实际的做法是在后处理阶段为容易混淆的类别增加类别置信度调整。如果模型对车门凹陷的置信度是 0.3对侧围划痕的置信度是 0.6可以设定输出侧围划痕因为现场维修方案对这两个类别的处置不同宁可选置信度更高的一侧。6. 数据增强与迁移学习的进阶用法6.1 针对性增强少样本类别再复制粘贴了车身缺陷数据集的硬伤永远是样本量尤其是少见类。YOLOv5 自带的 mosaic 增强在 640 输入下能把多张小图拼成一张等于变相增加样本量。但对于踏板损坏这种小目标mosaic 拼图后目标尺寸反而更小不利学习。我更倾向于对包含少数类的原图做局部裁剪把缺陷框放大后单独存成小图再作为额外训练图片加入数据集。在做局部裁剪时要注意剪出来的小图不能直接丢进训练集否则模型会对“目标占满全图”产生惯性。需要混合几种尺度有的裁剪块只含缺陷有的裁剪块包含缺陷周围 1.5 倍背景。这类局部增强配合--multi-scale训练能让模型在保持精度的同时不至于在整车身图上丢了小目标。6.2 迁移学习与学习率控制跑 30 轮就能看趋势车身缺陷和 COCO 数据集里的自然物体差异不小但低层特征仍有价值。迁移学习阶段的骨干特征已经学会边缘、纹理、色块剩下要做的是微调高层的语义特征。我会把骨干冻结期设为前 10 轮训练命令加--freeze 10让优化器只更新 head 部分防止初期大步长把预训练权重破坏掉。10 轮后解除冻结再使用--cos-lr让学习率沿余弦周期下降。从训练趋势看如果前 10 轮 cls_loss 没有明显下降问题基本不在超参而在数据标注错位。不要急着调学习率先回头检查 labels 目录下是否有多余的旧标注文件。另一条习惯是每次切数据集后先用 30 轮小跑验证整套流程不追求结果只看 loss 曲线有没有诡异的台阶。这套方法用在这份 7825 张数据上同样有效。从那以后我每次解压别人给的数据集都会强制自己先做一遍“标签与图像同名校验、类别编号重排、按场景划分”三件事再跑第一次训练。这十几分钟换掉的是训练十几个小时后才发现数据异常的后悔药。这套车身部件损坏车体缺陷检测数据集的 15 类划分方式和双格式目录结构值得直接拿去配你自己的业务需求。希望帮到你。本文还有配套的精品资源点击获取