尧图精选

轮胎缺陷检测数据集:VOC+YOLO双格式,4类缺陷实战指南

🕒 发布时间:2026/10/1 18:24:31 📁 来源:尧图网络
简介本资源为轮胎缺陷检测数据集面向从事工业质检、目标检测算法训练与深度学习课程实践的研究者及开发者可用于训练和验证轮胎表面缺陷识别模型。数据集同时提供Pascal VOC与YOLO两种标注格式包含jpg图片及一一对应的xml、txt标注文件标注工具为labelImg共设debris、ground、side、side_cut四个类别各类别框数分别为1599、564、188、493总框数2844类别分布清晰便于直接用于模型训练与评估。压缩包为7z格式内含约2000个文件以1999个xml标注文件和1个说明txt为主整体约105.65MB目录结构简洁方便按图片与标注对应关系快速检索。目前已有666人学习下载适合需要真实工业缺陷样本、希望快速搭建检测基线或开展数据增强实验的读者参考使用。1. 轮胎缺陷检测数据集2154 张 VOCYOLO 双格式4 类缺陷怎么落地拿到一份标注好的轮胎缺陷数据集最怕的不是数据量不够而是格式对不上、类别定义模糊、训练时 loss 震荡却找不到原因。这份 2154 张的轮胎缺陷检测数据集同时提供 Pascal VOC 的 xml 和 YOLO 的 txt 两种标注格式覆盖 debris、ground、side、side_cut 四个类别用 labelImg 标注总框数 2844。它解决的是轮胎表面缺陷检测从零标注成本高、类别不统一的问题适合做工业质检方向的目标检测训练、YOLO 系列模型微调以及缺陷检测算法的对比实验。如果你正在找一份能直接丢进 YOLOv5/v8 训练脚本、不用自己转格式的轮胎缺陷数据这份资源值得拆开看看。2. 拆包先看目录VOC 与 YOLO 双格式到底怎么对应2.1 文件结构里藏着的对应关系解压后你会看到三类文件混在一起jpg 图片、xml 标注、txt 标注。数量上三者都是 2154说明每张图都有一份 VOC 标注和一份 YOLO 标注没有漏标。xml 文件名形如firc_tire_1748.xml对应的图片就是firc_tire_1748.jpgYOLO 的 txt 也是同名。这种命名方式的好处是你写转换脚本或者做数据校验时直接按 basename 匹配就行不用维护额外的映射表。VOC 格式的 xml 里每个目标是一个object节点包含name类别名和bndbox的 xmin、ymin、xmax、ymax。YOLO 格式的 txt 每行是class_id x_center y_center width height坐标都归一化到 0~1。两种格式描述的是同一批框只是坐标系和存储方式不同。常见做法是训练时用 YOLO 格式做数据可视化或跟其他 VOC 数据集合并时用 xml。提示解压后先别急着改文件名保持原始命名后面写校验脚本会省很多事。2.2 四个类别的框数分布说明了什么类别名框数占比debris159956.2%ground56419.8%side1886.6%side_cut49317.3%debris 占了超过一半的框side 只有 188 个。这种不均衡在工业缺陷数据里很常见但直接训练会让模型偏向多数类。我一般会先算一下每个类别的框数如果最小类不到最大类的 1/5就考虑在损失函数里加类别权重或者对 side 类做少量过采样。不过这份数据里 side 虽然少但它是轮胎侧面缺陷跟 debris 的纹理差异大模型未必学不好先跑一版 baseline 看混淆矩阵再决定要不要调。2.3 用脚本校验图片与标注是否一一对应在训练之前花两分钟跑个校验脚本能避免训练到一半报“找不到标注”的错。下面这段代码检查 jpg、xml、txt 三者是否同名且数量一致顺便统计每个类别的框数。import os from collections import Counter import xml.etree.ElementTree as ET img_dir ./images # 存放 jpg 的目录 xml_dir ./annotations # 存放 xml 的目录 txt_dir ./labels # 存放 yolo txt 的目录 imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(.jpg)} xmls {os.path.splitext(f)[0] for f in os.listdir(xml_dir) if f.endswith(.xml)} txts {os.path.splitext(f)[0] for f in os.listdir(txt_dir) if f.endswith(.txt)} print(图片数:, len(imgs)) print(xml数:, len(xmls)) print(txt数:, len(txts)) print(图片有但xml缺失:, imgs - xmls) print(xml有但图片缺失:, xmls - imgs) print(图片有但txt缺失:, imgs - txts) # 统计 VOC 里每个类别的框数 counter Counter() for name in xmls: tree ET.parse(os.path.join(xml_dir, name .xml)) for obj in tree.findall(object): counter[obj.find(name).text] 1 print(类别框数:, dict(counter))这段脚本的逻辑很直接用集合做差集找出缺失项用 ElementTree 遍历 xml 统计类别。参数上img_dir、xml_dir、txt_dir按你解压后的实际目录改。如果输出里“图片有但xml缺失”不是空集说明有图没标训练时要么剔除这些图要么补标。类别框数如果跟摘要里的 1599/564/188/493 对不上说明数据被改动过需要重新确认。3. 转成 YOLO 训练格式从 VOC 到 txt 的完整流程3.1 为什么还要自己转一遍虽然数据集已经带了 YOLO 格式的 txt但实际训练时你往往需要把图片和标注按images/train、labels/train这样的目录结构放好还要生成data.yaml。另外如果你想把这份数据和别的 VOC 数据集合并就得统一转成 YOLO 格式再合并。所以掌握转换脚本比直接用现成 txt 更灵活。常见做法是写一个 VOC 转 YOLO 的脚本顺便做坐标裁剪防止框超出图片边界。3.2 VOC 转 YOLO 的坐标换算与边界处理VOC 的框是绝对坐标(xmin, ymin, xmax, ymax)YOLO 需要归一化的中心点和宽高。换算公式是x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h坑在于有些标注的 xmax 可能等于 img_w或者 xmin 小于 0归一化后会出现 1.0 或负数。YOLO 训练时对越界坐标比较敏感我一般会做一次 clip把坐标限制在 [0, 1] 内。import os import xml.etree.ElementTree as ET from PIL import Image classes [debris, ground, side, side_cut] class_to_id {c: i for i, c in enumerate(classes)} def voc_to_yolo(xml_path, img_path, out_txt_path): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_to_id: continue 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) # 裁剪到图片范围内 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) if xmax xmin or ymax ymin: continue # 跳过无效框 x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_to_id[cls_name]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines)) # 批量转换 for f in os.listdir(./annotations): if f.endswith(.xml): name os.path.splitext(f)[0] voc_to_yolo( os.path.join(./annotations, f), os.path.join(./images, name .jpg), os.path.join(./labels, name .txt) )这段代码里classes列表的顺序决定了 class_id必须跟data.yaml里的names顺序一致否则模型学到的类别会错位。clip那几行是血泪经验有些标注工具导出的框会超出图片 1~2 个像素不裁剪的话 YOLO 会警告甚至报错。if xmax xmin用来跳过宽高为负的无效框这种框在标注质量差的数据里偶尔出现。3.3 生成 data.yaml 与目录划分YOLOv5/v8 训练需要一份data.yaml指定训练集、验证集路径和类别名。我一般按 8:2 划分用脚本随机分。import os import random import shutil random.seed(42) all_imgs [f for f in os.listdir(./images) if f.endswith(.jpg)] random.shuffle(all_imgs) split int(len(all_imgs) * 0.8) train_imgs all_imgs[:split] val_imgs all_imgs[split:] for phase, files in [(train, train_imgs), (val, val_imgs)]: os.makedirs(f./dataset/images/{phase}, exist_okTrue) os.makedirs(f./dataset/labels/{phase}, exist_okTrue) for f in files: name os.path.splitext(f)[0] shutil.copy(f./images/{f}, f./dataset/images/{phase}/{f}) shutil.copy(f./labels/{name}.txt, f./dataset/labels/{phase}/{name}.txt) yaml_content path: ./dataset train: images/train val: images/val nc: 4 names: [debris, ground, side, side_cut] with open(./dataset/data.yaml, w) as f: f.write(yaml_content)random.seed(42)保证每次划分结果一致方便复现。nc: 4对应四个类别names的顺序必须跟转换脚本里的classes完全一致。划分完可以再跑一次校验确认 train 和 val 的图片数加起来等于 2154。4. 训练参数怎么设YOLOv8 在轮胎缺陷数据上的实操配置4.1 模型选型与输入尺寸轮胎缺陷检测属于工业质检缺陷目标通常不大debris 和 side_cut 的框面积可能只占图片的百分之几。这种场景下YOLOv8n 或 YOLOv8s 就够用没必要上 l 或 x因为数据量只有 2154 张大模型容易过拟合。输入尺寸我一般设imgsz640如果显存够可以试 768但 640 在精度和速度之间比较平衡。如果你用的是 YOLOv5--img 640同理。4.2 关键训练参数与含义yolo detect train \ data./dataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience20 \ workers4 \ device0 \ projectruns/tire \ nameexp1epochs100是上限配合patience20做早停验证集 loss 20 轮不降就停。lr00.01是初始学习率YOLOv8 默认就是 0.01如果 loss 一开始就炸可以降到 0.001。batch16按显存调8G 显存跑 yolov8s 加 640 尺寸16 差不多是上限。workers4是数据加载线程Windows 下如果报错就改成 0。device0指定第一块 GPUCPU 训练把 device 改成 cpu。4.3 训练过程中看什么指标启动训练后终端会打印每个 epoch 的 box_loss、cls_loss、dfl_loss 和 mAP50。box_loss 下降说明框在收敛cls_loss 下降说明分类在收敛。如果 box_loss 震荡不降先检查标注坐标有没有归一化错误再检查学习率是不是太大。mAP50 在 50 轮左右应该能看到明显上升如果一直低于 0.1大概率是 data.yaml 的 names 顺序跟 txt 里的 class_id 对不上。我习惯在训练前用yolo detect train加--verbose打一批样本出来看确认框画在正确的位置。注意YOLOv8 的names顺序如果跟 txt 里的 class_id 不一致模型会把 debris 学成 sidemAP 会低得离谱但 loss 看起来正常这个坑很隐蔽。5. 避坑与排查这份数据集最容易翻车的五个地方5.1 现象训练报 “No labels found”原因YOLO 默认在images同级目录找labels如果你的目录结构是images/train和labels/train分开但路径没在 data.yaml 里写对就会找不到。解决确认 data.yaml 里train: images/train和val: images/val是相对path的路径且labels目录跟images同级同名。5.2 现象mAP 一直为 0 或极低原因class_id 跟 names 顺序错位或者 txt 里的坐标没有归一化。解决打开一个 txt 看数值如果 x_center 大于 1说明没归一化如果 class_id 出现 4 或更大说明类别数对不上。用 3.2 的脚本重新转一遍。5.3 现象训练到一半 loss 变成 nan原因学习率太大或者标注里有宽高为 0 的框。解决把 lr0 降到 0.001并在转换脚本里加if w 0 or h 0: continue过滤掉无效框。5.4 现象验证集图片有标注但模型不检测原因验证集的 txt 文件没有跟图片一起复制过去或者复制时文件名大小写不一致。解决跑一遍 2.3 的校验脚本检查 val 目录下 jpg 和 txt 是否一一对应。5.5 现象Windows 下训练报 “DataLoader worker exited unexpectedly”原因Windows 的 multiprocessing 跟 PyTorch DataLoader 兼容性问题。解决把workers设为 0训练速度会慢一点但不会崩。6. 进阶技巧用混淆矩阵反推标注质量与类别权重训练完一版之后别只看 mAP把混淆矩阵导出来看。YOLOv8 训练结束会在runs/tire/exp1下生成confusion_matrix.png。如果 debris 和 ground 之间互相误判很多说明这两类的纹理在图片里太像可能需要加更多 ground 的样本或者在损失里给 ground 更高的权重。如果 side 的召回率特别低但精确率还行说明模型对 side 太保守可以适当降低 side 的置信度阈值。我一般会跑两版对比第一版不加类别权重第二版在data.yaml里加cls_pw或者用--class_weights给 side 和 ground 加权。对比两版的混淆矩阵看少数类的召回有没有提升。如果提升不明显说明问题不在权重而在标注本身——可能 side 的框画得太松把背景也框进去了。这时候就得回去抽查 side 类的 xml看 bndbox 是不是贴紧了缺陷边缘。还有一个技巧是用yolo detect val加--save-json导出预测结果跟原始标注做 IoU 匹配统计每个类别的漏检和误检。漏检多的类别要么加数据要么调低置信度阈值误检多的类别要么加负样本要么调高阈值。这套流程走下来基本能把这份轮胎缺陷数据集的潜力榨干。从那以后我每次拿到新数据集都强制先跑一遍文件校验和类别统计再画一批标注框出来肉眼过一遍最后才开训练。这个习惯帮我省了至少三次通宵排查的功夫。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →