简介:这份资源是面向计算机视觉开发者与工业质检方向学习者的轮胎缺陷检测数据集,采用Pascal VOC与YOLO双格式标注,可直接用于目标检测模型的训练、验证与算法对比实验,适合具备一定深度学习基础、正在做缺陷检测项目或课程设计的人员使用。压缩包内共约2000个文件,以1999个xml标注文件和1个说明用txt为主,整体大小约105.65MB,另配套2154张jpg图片及对应的yolo格式txt标注,图片与标注一一对应,无需额外转换即可接入主流检测框架。数据集共标注debris、ground、side、side_cut四类缺陷,框数分别为1599、564、188、493,总框数2844,标注由labelImg完成,类别分布清晰,便于分析长尾问题与调整采样策略。目前已有666人学习下载,可作为轮胎表面缺陷识别、工业异常检测等任务的练手与基线复现素材,帮助读者快速搭建数据管线、验证模型效果并积累调参经验。
1. 轮胎缺陷检测数据集:2154 张 VOC+YOLO 双格式到底能跑出什么结果
拿到一个标注好的轮胎缺陷检测数据集,第一反应通常不是「太好了」,而是「这 2154 张到底够不够、四个类别分得开吗、VOC 和 YOLO 两套格式该用哪个」。轮胎缺陷检测在工业质检里属于典型的小目标、低对比度、类间差异细微的场景,缺陷区域往往只占整张图很小一块,背景纹理又高度重复。这个数据集提供 VOC 和 YOLO 两种标注格式、共 2154 张图、4 个缺陷类别,本质上解决的是「从零搭建轮胎表面缺陷检测模型时,标注数据从哪来」的问题。它适合两类人:一是想快速验证 YOLO 系列在自己产线图像上能不能用的算法工程师,二是需要一份带边界框标注的工业缺陷数据来做课程设计或方案预研的开发者。下面按「先看清数据长什么样、再决定怎么训、最后避开标注和训练里的坑」这条线走一遍。
2. 拆开压缩包之前:VOC 与 YOLO 双格式的差异与选型
2.1 两种格式的目录结构和标注逻辑
VOC 格式的核心是每张图对应一个同名 XML 文件,标注信息写在<object>节点里,包含类别名和边界框的xmin/ymin/xmax/ymax四个像素坐标。YOLO 格式则是每张图对应一个同名 txt 文件,每行一个目标,格式是类别索引 中心x 中心y 宽 高,四个值全部归一化到 0 到 1 之间。这两种格式描述的是同一批标注,只是坐标系和存储方式不同。VOC 保留绝对像素坐标,方便回溯原图尺寸;YOLO 归一化后与图像分辨率解耦,训练时不用再做缩放换算。
一个 2154 张、4 类别的数据集,如果按 VOC 组织,目录大致是Annotations/放 XML、JPEGImages/放原图、ImageSets/Main/放训练验证划分。如果按 YOLO 组织,通常是images/和labels/两个平行目录,再加一个classes.txt或data.yaml记录类别名。压缩包里同时给两套,意味着你可以直接用 YOLO 格式开训,也可以用 VOC 格式接那些只吃 XML 的老框架。
2.2 选 VOC 还是 YOLO:看你的训练框架和后续需求
选型其实不复杂。用 Ultralytics 系的 YOLOv5/v8/v11 训练,直接上 YOLO 格式,省掉转换步骤。用 PaddleDetection、MMDetection 或者一些传统机器视觉流程,VOC 格式兼容性更好。如果你后面要做数据增强后重新生成标注,VOC 的绝对坐标更容易做几何变换的校验,YOLO 的归一化坐标在旋转、裁剪后需要重新归一化,容易出错。
提示:两套格式的类别顺序必须一致。VOC 里类别靠名字匹配,YOLO 里靠索引匹配,一旦
classes.txt的顺序和 XML 里类别名的字母序对不上,训练出来的模型会把类别搞混,而且这种错误在 loss 曲线上看不出来。
我一般会先做一次交叉校验:随机抽 20 张图,把 YOLO 的归一化坐标还原成像素坐标,和对应 XML 的xmin/ymin/xmax/ymax对比,误差超过 2 个像素就说明转换环节有问题。这个检查花不了几分钟,但能挡掉后面几小时的无效训练。
2.3 用脚本做一次格式交叉校验
import os import xml.etree.ElementTree as ET from PIL import Image # 校验 VOC XML 与 YOLO txt 是否描述同一批标注 def voc_to_xyxy(xml_path): tree = ET.parse(xml_path) root = tree.getroot() size = root.find('size') w, h = int(size.find('width').text), int(size.find('height').text) boxes = [] for obj in root.findall('object'): name = obj.find('name').text bnd = obj.find('bndbox') xmin = float(bnd.find('xmin').text) ymin = float(bnd.find('ymin').text) xmax = float(bnd.find('xmax').text) ymax = float(bnd.find('ymax').text) boxes.append((name, xmin, ymin, xmax, ymax)) return w, h, boxes def yolo_to_xyxy(txt_path, img_w, img_h): boxes = [] with open(txt_path) as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cls_id, cx, cy, bw, bh = map(float, parts) xmin = (cx - bw / 2) * img_w ymin = (cy - bh / 2) * img_h xmax = (cx + bw / 2) * img_w ymax = (cy + bh / 2) * img_h boxes.append((int(cls_id), xmin, ymin, xmax, ymax)) return boxes # 抽样校验 sample_ids = ['000001', '000002', '000003'] # 替换为实际文件名 for sid in sample_ids: xml_path = f'Annotations/{sid}.xml' txt_path = f'labels/{sid}.txt' img_path = f'JPEGImages/{sid}.jpg' if not all(os.path.exists(p) for p in [xml_path, txt_path, img_path]): continue img = Image.open(img_path) w, h, voc_boxes = voc_to_xyxy(xml_path) yolo_boxes = yolo_to_xyxy(txt_path, w, h) print(f'{sid}: VOC {len(voc_boxes)} boxes, YOLO {len(yolo_boxes)} boxes') for vb, yb in zip(voc_boxes, yolo_boxes): diff = max(abs(vb[1]-yb[1]), abs(vb[2]-yb[2]), abs(vb[3]-yb[3]), abs(vb[4]-yb[4])) if diff > 2: print(f' 坐标偏差过大: {diff:.1f}px, VOC={vb}, YOLO={yb}')这段脚本做的是逐框对比。voc_to_xyxy从 XML 里读出图像宽高和绝对坐标,yolo_to_xyxy把归一化坐标乘回图像宽高还原成像素坐标。两个列表按顺序配对后算最大偏差,超过 2 像素就报警。参数上唯一需要注意的是图像宽高必须从原图读取,不能硬编码,因为不同批次采集的轮胎图像分辨率可能不一致。如果校验通过,说明两套格式描述一致,可以放心选一套用。
3. 用 YOLOv8 在 2154 张轮胎缺陷图上跑通训练
3.1 数据集划分与 data.yaml 配置
2154 张图按 8:1:1 划分,训练集约 1723 张,验证集 215 张,测试集 216 张。划分时要注意同一轮胎、同一拍摄批次的图像不能同时出现在训练集和验证集里,否则验证指标会虚高。如果数据里有连续帧或同一位置的多角度拍摄,按轮胎编号分组划分更稳妥。
YOLO 格式的data.yaml是训练的入口配置:
path: /data/tire_defect train: images/train val: images/val test: images/test nc: 4 names: 0: bubble 1: crack 2: foreign_object 3: wearpath是数据集根目录,train/val/test是相对路径。nc是类别数,必须和实际标注的类别数一致。names的索引顺序必须和 YOLO txt 里的类别索引严格对应,这个顺序一旦写错,模型学到的就是错位的类别映射。我一般会在生成data.yaml之前先统计一遍所有 txt 里出现过的类别索引,确认最大值等于nc-1,且每个索引都有对应样本。
3.2 训练命令与关键参数设置
yolo detect train \ data=/data/tire_defect/data.yaml \ model=yolov8s.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ patience=30 \ device=0 \ project=runs/tire \ name=exp01model=yolov8s.pt用的是预训练权重,2154 张图从零训容易过拟合,预训练能显著加快收敛。imgsz=640是输入分辨率,轮胎缺陷区域小,如果显存允许可以提到 960 或 1280,小目标召回会明显改善。batch=16在单张 8G 显存卡上比较稳,显存不够就降到 8 并配合accumulate做梯度累积。lr0=0.01是初始学习率,lrf=0.01是最终学习率系数,余弦退火到初始值的百分之一。patience=30表示验证指标 30 轮不提升就早停,避免无效训练。
注意:
imgsz必须是 32 的整数倍,否则 YOLO 内部会报维度不匹配。640、960、1280 都是安全值。
训练启动后重点看三个信号:box_loss是否稳定下降、mAP50是否在 50 轮内超过 0.5、验证集的cls_loss是否和训练集差距过大。如果box_loss震荡不降,先检查标注框有没有越界或宽高为负的情况。如果mAP50卡在低位,多半是类别不平衡或小目标太多,需要调imgsz或做针对性增强。
3.3 训练结果解读与混淆矩阵排查
训练结束后runs/tire/exp01/下会生成confusion_matrix.png、results.png和weights/best.pt。混淆矩阵是排查类别混淆的第一手材料。4 个类别如果出现某一类大量被预测成背景,说明该类样本太少或标注质量差;如果两类之间互相混淆严重,说明它们在视觉上区分度不够,需要补充难例或调整类别定义。
from ultralytics import YOLO model = YOLO('runs/tire/exp01/weights/best.pt') metrics = model.val(data='/data/tire_defect/data.yaml', split='test') print(f'mAP50: {metrics.box.map50:.4f}') print(f'mAP50-95: {metrics.box.map:.4f}') for i, name in enumerate(metrics.names.values()): print(f'{name}: AP50={metrics.box.ap50[i]:.4f}')这段代码加载最优权重在测试集上跑一次验证,输出整体和各类别的 AP。metrics.box.ap50是按类别索引排列的数组,顺序和data.yaml里的names一致。如果某一类 AP 明显低于其他类,优先检查该类别的标注框数量是否过少,以及标注框是否普遍偏小。轮胎缺陷里裂纹和磨损这两类在灰度图上对比度接近,混淆概率高,可以考虑在数据增强里加对比度扰动。
4. 轮胎缺陷检测训练避坑:5 个真实踩过的坑
4.1 坑一:YOLO 类别索引与 names 顺序错位
现象:训练 loss 正常下降,但推理时所有预测框的类别都是错的,比如裂纹被标成气泡。
原因:生成 YOLO txt 时用的类别索引顺序和data.yaml里names的顺序不一致。常见于从 VOC 转换时按文件夹遍历顺序分配索引,而data.yaml手写时按字母序排列。
解决:写一个统计脚本,遍历所有 txt 收集出现过的类别索引,再和data.yaml的names长度对比。更稳妥的做法是从classes.txt统一生成data.yaml,保证两边同源。
4.2 坑二:小目标缺陷在 640 分辨率下大量漏检
现象:mAP50能到 0.7 左右,但实际推理时小面积缺陷几乎检不出来,可视化后发现小目标框全部丢失。
原因:轮胎缺陷里细小裂纹和点状异物在原图上可能只有十几个像素,缩放到 640 后特征几乎消失。YOLO 的 P3 特征图 stride 是 8,对应最小检测尺度约 8 像素,再小就无能为力。
解决:把imgsz提到 960 或 1280,同时开启mosaic和copy_paste增强。如果显存不够,改用 YOLOv8 的s以下模型或者切图推理。另一个办法是在标注阶段就把过小的目标合并或剔除,避免模型被无法学习的样本干扰。
4.3 坑三:验证集指标虚高,实际产线翻车
现象:验证集mAP500.85,部署到产线后误检率极高,大量正常轮胎被判为缺陷。
原因:数据集划分时同一轮胎的多张图被分到了训练集和验证集,模型记住了这个轮胎的背景特征,验证集相当于在「见过的轮胎」上测试。产线上遇到新轮胎,背景分布变了,模型就崩了。
解决:按轮胎编号或拍摄批次做分组划分,确保同一轮胎只出现在一个子集里。如果数据里没有编号信息,按图像采集时间排序后做间隔划分,避免连续帧泄漏。
4.4 坑四:标注框越界导致训练中途报错
现象:训练跑到几十轮突然报RuntimeError: box coordinate out of range或 loss 变成 NaN。
原因:VOC 转 YOLO 时,某些标注框的xmax超过了图像宽度,归一化后中心坐标加半宽大于 1,YOLO 内部计算 IoU 时出现非法值。
解决:转换脚本里加一道裁剪逻辑,把xmin/xmax限制在[0, w],ymin/ymax限制在[0, h],再重新归一化。转换完成后统计一遍所有框的宽高,出现 0 或负值直接定位到对应文件人工复核。
4.5 坑五:类别不平衡导致少数类几乎学不到
现象:4 个类别里某一类样本只有几十张,训练后该类 AP 接近 0,混淆矩阵里全部被预测成其他类或背景。
原因:YOLO 默认的分类损失对所有类别等权,少数类梯度被多数类淹没。
解决:在data.yaml同级目录建一个hyps.yaml,调低cls损失权重的同时对少数类做过采样。更直接的办法是用copy_paste增强把少数类样本复制粘贴到其他图上,扩充到和其他类同一量级。如果少数类确实难以扩充,考虑合并到语义相近的类别里,减少类别数。
5. 把 2154 张用到极致:小样本下的增强策略与验证习惯
2154 张 4 类别,平均每类五百多张,在工业缺陷检测里算中等偏少。想让模型真正可用,光靠默认增强不够。我一般会在 YOLO 自带增强之外再加两层:一是针对轮胎表面纹理的blur和brightness扰动,模拟不同光照和镜头状态;二是针对缺陷形态的elastic_transform,让裂纹和磨损的边界产生形变,提升模型对形状变化的鲁棒性。
import albumentations as A import cv2 transform = A.Compose([ A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.3), A.RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2, p=0.5), A.GaussNoise(var_limit=(10.0, 50.0), p=0.3), A.ElasticTransform(alpha=1, sigma=50, p=0.2), A.Rotate(limit=15, p=0.3), ], bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels'])) img = cv2.imread('JPEGImages/000001.jpg') with open('labels/000001.txt') as f: lines = [l.strip().split() for l in f if l.strip()] bboxes = [[float(x) for x in l[1:]] for l in lines] labels = [int(l[0]) for l in lines] aug = transform(image=img, bboxes=bboxes, class_labels=labels) print(f'增强后框数: {len(aug["bboxes"])}')这段增强用 albumentations 做,BboxParams指定format='yolo'后,边界框会随图像变换自动调整。ElasticTransform的alpha控制形变强度,sigma控制平滑度,轮胎缺陷建议alpha=1, sigma=50,太强会让缺陷形态失真。Rotate限制在 15 度以内,因为轮胎图像通常有固定拍摄角度,大角度旋转会产生不真实的样本。
验证习惯上,我坚持做两件事。第一,每次训练完在测试集上跑一遍逐类 AP,记录到表格里,对比不同实验的类别短板。第二,从测试集里抽 30 张做人工复核,把漏检和误检的图单独存一个badcase/目录,下一轮训练前优先对这些场景做增强或补标。这个习惯坚持几轮后,模型在产线上的误检率通常能降一半以上。
| 增强手段 | 推荐参数 | 适用缺陷类型 | 注意事项 |
|---|---|---|---|
| 亮度对比度扰动 | brightness 0.2, contrast 0.2 | 全部 | 过强会掩盖低对比度缺陷 |
| 高斯噪声 | var 10-50 | 裂纹、异物 | 噪声过大会被误学成缺陷 |
| 弹性形变 | alpha=1, sigma=50 | 裂纹、磨损 | 强度过大会产生非真实形态 |
| 旋转 | limit=15 | 全部 | 超过 15 度与拍摄角度不符 |
| 水平翻转 | p=0.5 | 全部 | 轮胎纹理通常对称,安全 |
最后说一个我自己的教训:早期做轮胎缺陷检测时,我花了两周调模型结构,结果提升还不如把 200 张漏标和错标的图重新标一遍。数据质量的上限决定了模型的上限,2154 张图里如果有百分之五的标注有问题,再好的增强和调参都是在噪声上拟合。每次开训前花半天做标注抽检,比训练中途反复调参划算得多。希望帮到你。
本文还有配套的精品资源,点击获取