
简介面向轮胎外观缺陷检测的目标检测数据集包含2154张轮胎图像及配套的Pascal VOC与YOLO双格式标注覆盖debris、ground、side、side_cut四个缺陷类别总计2844个标注框适用于工业产线质检、表面缺陷识别等场景下YOLO系列模型的训练与效果对比。压缩包共2000个文件以XML标注文件占绝对主体另附1个TXT使用说明整体约105.65MB解压后即可接入现有训练脚本。标注由labelImg工具生成资源同时提供逐类框数统计如debris 1599框、ground 564框、side 188框、side_cut 493框有助于判断类别分布并调整损失函数权重文件按原始命名保留对应关系可降低数据清洗和格式转换成本。已有667人学习下载适合具备目标检测基础的算法工程师、研究者及学生用于轮胎缺陷识别领域的快速验证与实验扩展。1. 轮胎缺陷检测数据集到底值不值得用2154张、VOCYOLO、4类做轮胎质检项目的朋友十有八九都卡在同一个地方现场拍了上千张图片但标注得自己手工画框画到半夜才一两百张。这时候看到「轮胎缺陷检测数据集VOCYOLO格式2154张4类别.7z」第一反应是这东西能不能直接用。我的回答是能但别幻想拿过来就能上线。它给你的是2154张带标签的轮胎图像同时存了VOC的xml和YOLO的txt两套标注四个缺陷类别。适合做几件事评估YOLO系列模型在这个场景的baseline、做迁移学习预训练、或者给你的私有数据扩充训练样本。后面我会从头拆解这个包怎么解压、格式怎么转换、训练怎么跑以及最容易翻车的几个坑。2. 拆开7z压缩包VOC与YOLO两种格式的目录结构和标注内容2.1 解压7z文件Linux和Windows两条路都要走通你拿到的是一整个.7z压缩包不是直接能用的文件夹。第一步永远是解压这一步就能劝退不少人。Linux下最常用的是p7zip工具命令很直接# Debian/Ubuntu 安装 p7zip sudo apt install p7zip-full # 解压到指定目录避免压出来的文件散落一地 7z x 轮胎缺陷检测数据集VOCYOLO格式2154张4类别.7z -o./tire_defect_dataWindows下我会用7-Zip图形界面右键解压到当前文件夹。但要注意如果你在PyCharm里跑训练脚本最好把解压后的目录放到纯英文路径下别放在「桌面/新建文件夹」这种带中文和空格的地方否则后面DatasetNotFound会找得你怀疑人生。解压完成后先看目录树常见做法是里面至少有三个子目录存放jpg原图的JPEGImages、存放VOC格式xml标注的Annotations、存放YOLO格式txt标注的labels外加一个classes.txt或obj.names写明四个类别名。看不到classes.txt也不用慌从任意一个xml里就能把类别全部捞出来后面有脚本。2.2 VOC格式的XML标注object节点里的name和bndbox是核心VOC格式是标注工具LabelImg的默认输出每个xml文件对应一张图片。用文本编辑器打开任意一个xml你会看到类似这样的结构annotation filenametire_0001.jpg/filename size width1024/width height768/height /size object namecrack/name bndbox xmin120/xmin ymin300/ymin xmax450/xmax ymax510/ymax /bndbox /object /annotation这里name是缺陷类别bndbox里是左上角和右下角的像素坐标。注意不同数据集的类别名可能不一样有的叫crack裂纹有的叫bubble气泡有的是拼音以你解压后看到的实际内容为准。我这个示例只是为了说明结构千万别拿我的crack去套你的classes文件。xml里的坐标都是绝对像素值范围受size约束这就是VOC格式的特点。2.3 YOLO格式的TXT标注归一化坐标和类别索引YOLO格式的txt每一行是一个目标格式固定为class_id x_center y_center width height后面四个值都是归一化到0~1的浮点数用像素值除以图片宽高得到。比如0 0.2783 0.5273 0.3223 0.2734含义是类别索引为0的缺陷其中心点位于图片宽度的27.83%、高度的52.73%处框的宽度为图片宽度的32.23%高度为图片高度的27.34%。为什么强调归一化因为YOLO训练时读入的图片会被缩放到imgsz指定尺寸比如640x640只有归一化坐标才能在不同分辨率下保持一致。如果你把VOC的绝对坐标直接喂给YOLO不换算训练会直接崩掉或产生大量无效框。2.4 统计4个类别有多少目标先看清家底再谈训练拿到数据集第一件事不是训练而是统计。我一般会用脚本把VOC的xml全部扫一遍看看四个类别各有多少个目标框有没有某个类别只有几十个框的极端不平衡。统计脚本很简单import xml.etree.ElementTree as ET from pathlib import Path ann_dir Path(Annotations) counts {} for xml_file in ann_dir.glob(*.xml): tree ET.parse(xml_file) for obj in tree.findall(object): name obj.find(name).text.strip() counts[name] counts.get(name, 0) 1 print(counts)运行后会输出类似{crack: 3200, bubble: 1500, foreign_matter: 800, wear: 600}这样的字典。注意这里统计的是目标框数量不是图片张数因为一张图里可能同时有多个缺陷。如果你发现某个类别目标框数量比其它类别少一个数量级后面训练时就要考虑类别权重、过采样或者用更小的模型先试否则模型很容易忽略稀有类别。3. VOC和YOLO格式互转转换脚本、数据划分与四个边界坑3.1 为什么数据集要同时提供VOC和YOLO两套标注很多标注工具原生输出VOC但YOLO系列的训练框架只认txt。数据集打包者给你两套格式是想省去你自己转换的功夫。但实际使用中你还是得自己再处理一遍因为两套标注的目录组织、类别顺序、甚至某个文件是否完好都需要验证。常见做法是用VOC的xml作为唯一事实来源做任何转换都以它为准不要直接改txt。因为xml里有图片尺寸信息能直接换算而txt里的归一化坐标本身已经把尺寸抹掉了出了问题很难还原。3.2 VOC转YOLO的Python脚本解析XML并归一化以下脚本是我每次拿到VOC数据集都会跑的把Annotations下所有xml转成labels下的txt并同时生成一份classes.txtimport xml.etree.ElementTree as ET from pathlib import Path # 读取类别列表每行一个类别名顺序决定类别ID class_names [line.strip() for line in Path(classes.txt).read_text().splitlines()] def voc_to_yolo(xml_file, out_txt, class_names): tree ET.parse(xml_file) 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.findall(object): name obj.find(name).text.strip() if name not in class_names: continue # 遇到未知类别跳过而不是崩溃 cls_id class_names.index(name) 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 width (xmax - xmin) / img_w height (ymax - ymin) / img_h # 边缘坐标可能因标注溢出到[0,1]外这里截断 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) width min(width, 1.0) height min(height, 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) out_txt.write_text(\n.join(lines)) # 遍历所有xml for xml_file in Path(Annotations).glob(*.xml): txt_path Path(labels) / (xml_file.stem .txt) voc_to_yolo(xml_file, txt_path, class_names)这段代码有三个关键点。第一class_names的顺序绝对不能乱YOLO的类别ID就是列表索引训练框架按ID读取类别名一旦顺序和训练时的data.yaml不一致模型的输出语义就全错了。第二坐标换算用的是中心点加宽高而不是VOC的左上右下容易算错。第三我加了越界截断因为轮胎图像边缘的缺陷框经常画到图外不截断会导致训练时出现NaN损失。3.3 YOLO转VOC的逆向脚本可视化复核时才能用YOLO转VOC不常用但当你需要把模型预测结果导回LabelImg检查时就需要把txt再变回xml。逆向逻辑反过来读取图片宽高把归一化坐标乘以宽高得到像素坐标再构造xml。脚本我就不完整贴了但你一定要记住YOLO的txt里没有图片尺寸转回VOC前必须从图片本身获取宽高否则转出来的框全部错位。常见做法是提前把所有图片的宽高存成一个字典用PIL.Image.open(img_path).size读取。3.4 数据划分train/val/test的比例与随机种子训练前必须划分数据集而且要保证划分后图片和标注文件名一一对应。我一般用80%训练、20%验证测试集从训练集中再抽或者直接用验证集顶替。更稳妥的按缺陷类别分层采样避免某个类别全被分到验证集。下面是复制文件到YOLO约定目录的脚本import random from pathlib import Path from shutil import copy2 random.seed(42) # 固定种子保证每次划分一致 image_paths list(Path(JPEGImages).glob(*.jpg)) random.shuffle(image_paths) n len(image_paths) train_ratio 0.8 val_ratio 0.2 train_files image_paths[:int(n * train_ratio)] val_files image_paths[int(n * train_ratio):int(n * train_ratio) int(n * val_ratio)] def organize(files, subset): img_out Path(ftire_dataset/{subset}/images) lbl_out Path(ftire_dataset/{subset}/labels) img_out.mkdir(parentsTrue, exist_okTrue) lbl_out.mkdir(parentsTrue, exist_okTrue) for img_path in files: copy2(img_path, img_out / img_path.name) txt_path Path(labels) / (img_path.stem .txt) if txt_path.exists(): copy2(txt_path, lbl_out / txt_path.name) organize(train_files, train) organize(val_files, val)这个脚本把图片和同名txt一起复制到新目录符合YOLO训练框架对数据目录的预期images和labels兄弟目录文件名一一对应。如果你发现有些图片没有对应的txt那说明这张图没有目标训练框架一般会忽略但最好单独建一个空txt或者直接删掉这张图否则验证时mAP计算会报错。4. 用YOLOv8在轮胎缺陷数据集上快速跑通训练4.1 安装Ultralytics与准备数据集YAML环境搭建很简单我推荐直接用Ultralytics YOLOv8它把训练、验证、导出封装成一条命令。先装包pip install ultralytics然后准备好数据集描述文件tire.yaml内容如下path: ./tire_dataset train: images/train val: images/val nc: 4 names: 0: crack 1: bubble 2: foreign_matter 3: wear注意names里的顺序和刚才classes.txt必须完全一致。如果你的包内classes顺序不同按实际改。nc是类别数这个数据集固定是4。4.2 训练参数与损失函数的关系imgsz、batch、epochs怎么定训练参数不是随便填的它们直接影响YOLO的损失函数收敛。YOLOv8的损失由三部分组成分类损失BCE、边界框回归损失CIoU、置信度损失。imgsz决定了输入分辨率轮胎缺陷里很多是细小裂纹如果原图是1024x1024而你设imgsz640一个小裂纹可能只有几个像素损失函数根本学不到有效特征。我一般先用imgsz640跑个20轮看趋势如果验证集召回率偏低再上imgsz1024。batch大小和显存挂钩batch太小会导致BN层统计不稳定损失震荡batch太大又会把显存吃满用batch16起步比较稳妥。epochs建议300起步配合早停patience50因为工业缺陷数据量不大模型容易在100轮内过拟合。4.3 训练命令与关键日志从loss曲线判断拟合状态有了yaml就可以开训yolo train datatire.yaml modelyolov8n.pt epochs300 imgsz640 batch16 device0 patience50这里我选了yolov8n作为起点因为它参数量最小跑得快能快速验证数据格式是否正确。跑之前一定要先看一眼日志里的BoxP、ClsP、DFL几个loss值如果第一个epoch就是NaN百分之九十九是标注坐标越界或者类别ID超出nc。训练中每过几个epoch终端会打印验证集的mAP50-95我会盯着train/val的loss曲线如果train loss一路下降而val loss在第几十轮开始反弹那就是过拟合信号这时候需要加大数据增强或减小模型复杂度。4.4 验证与导出用最佳权重看预测效果训练结束后Ultralytics会在runs/detect/train/weights/下生成best.pt和last.pt。我习惯先跑验证集确认mAP不是靠某一大类撑起来的yolo val modelruns/detect/train/weights/best.pt datatire.yaml这条命令会输出每个类别的mAP50和mAP50-95如果某个类别的mAP比其他类别低一大截就说明这个类别的样本量或特征不够。然后可视化预测yolo predict modelbest.pt sourcetire_dataset/val/images --save-txt --save-conf在runs/detect/predict下会生成带框的预测图我会快速翻一遍重点看有没有大量重复框或漏检框这比看指标更直观。5. 轮胎缺陷检测训练避坑5条血泪经验5.1 解压后目录名带中文或空格导致DatasetNotFound现象运行训练命令后报错Dataset not found或者FileNotFoundError明明路径存在却读不到。原因Ultralytics内部用pathlib解析路径中文和空格会被转义Windows下更严重PyCharm的终端和系统编码不一致也会导致路径乱码。解决把解压后的目录重命名为全英文例如tire_defect_data路径中不要有空格、括号、中文。以后所有命令都用相对路径别用绝对路径。5.2 类别编号与classes.txt顺序不一致训练log正常但预测全错现象loss能正常下降验证mAP也不错但用模型预测新图时明明是裂纹输出标签却是气泡。原因你手里的classes.txt可能是别人用obj.names生成的顺序和VOC xml里name的字典序不一致。YOLO的类别ID纯粹是索引不管你是crack还是bubbleID0就是第一个类。转换脚本如果按xml里第一次出现的顺序生成ID而不是按某个固定顺序就会乱。解决永远从VOC xml重新统计类别人工确定顺序后写入classes.txt和tire.yaml然后重新执行转换脚本。不要直接修改txt的ID很容易错位。5.3 小缺陷目标在imgsz640下漏检严重召回率上不去现象训练完验证mAP50看起来还行但实际生产环境下裂纹一个都测不出来一查per-class recall小目标类别只有0.2。原因轮胎图像的分辨率往往超过2000x2000而训练默认缩放到640x640一个细裂纹在缩放后可能只剩2~3个像素宽特征完全丢失。解决对于这类小目标数据集我一般把imgsz提高到1024或1280。显存不够就用yolov8n或减少batch8。另一个有效方法是做切片推理把原图切成重叠的patch分别检测再把结果合并但训练时最好也配合切片增强否则训练和推理的尺度不一致。5.4 单通道灰度图被误判为三通道训练中途报错shape不匹配现象训练到一半报错shape mismatch: expected 3 channels, got 1或者pytorch RuntimeError。原因轮胎X光或超声图像经常是单通道灰度图而YOLO的预处理默认用三通道RGB读取。如果数据集中混着灰度图和三通道图cv2.imread读出来的形状不一致collate时就会炸。解决写一个预处理脚本把所有图片统一转为RGB三通道并另存from PIL import Image from pathlib import Path for img_path in Path(JPEGImages).glob(*): img Image.open(img_path) if img.mode ! RGB: img img.convert(RGB) img.save(img_path)注意覆盖保存前先备份不然转错了没后悔药。这一步是很多工业数据集的隐藏坑因为拍照设备输出格式不统一。5.5 数据增强过头导致缺陷纹理变形失真现象训练集mAP很高验证集mAP也不差但一到现场新图片就翻车预测框乱跑。原因Ultralytics默认开启一大堆数据增强包括随机旋转、透视变换、HSV扰动。轮胎表面的纹理是有方向性的比如胎纹的沟槽旋转90度后就不再是轮胎了缺陷的形态也会因透视变换而严重拉伸模型学到的是「变形后的缺陷」而不是真实缺陷。解决在tire.yaml同级写一个tire_aug.yaml只保留轻微的翻转和微调对比度augment: false fliplr: 0.5 flipud: 0.0 hsv_h: 0.0 hsv_s: 0.0 hsv_v: 0.0 translate: 0.0 scale: 0.0训练命令加上cfgtire_aug.yaml。我见过好几个项目因为增强过头训练时mAP刷到0.95现场实测直接归零这种玄学问题最浪费工时。6. 验证细节用混淆矩阵和多尺度推理把召回提上去训练完不是终点验证方法和调优策略才是决定这个数据集能不能落地的关键。Ultralytics在验证后会在runs/detect/val/下生成confusion_matrix.png这张图你要仔细看。对角线是正确分类如果某一行除了对角线外还有一堆亮色说明这类缺陷经常被误判成另一类。比如轮胎的bubble气泡和foreign_matter异物在灰度图上纹理接近混淆矩阵里这两个格子就会很亮。一旦发现这种混淆我通常的做法是合并类别重新训练或者为这两个类别增加专门的数据增强。另一个必须做的验证是按尺寸分桶统计召回率。把验证集图片按缺陷框的像素面积分成三个桶小目标小于32x32、中目标32x32~96x96、大目标大于96x96分别计算召回率。如果小目标桶的召回率远低于其他桶说明模型对小缺陷感知不足这时候多尺度推理往往比换更大模型更有效。具体做法是用yolov8m同时开启imgsz640和imgsz1280预测同一张图把两次的检测框按置信度阈值合并置信度超过0.5的框保留再用NMS去重。这个trick能让小目标召回率提升5~10个点。用这个数据集训练时我还养成一个习惯每个epoch结束后不光看mAP还随机抽10张验证集图片输出预测结果肉眼确认缺陷有没有被框对。有一次mAP50从0.78涨到0.85但抽图一看模型把轮胎边缘的阴影全当成了裂纹正负样本失衡带来的虚警被mAP掩盖了。从那以后我坚持把「抽图看检测效果」当作硬性验证步骤这比任何指标都可靠。希望帮到你。本文还有配套的精品资源点击获取