2026/10/11 5:24:07

布料缺陷破洞污渍检测数据集:1690张VOC+YOLO双格式使用指南

布料缺陷破洞污渍检测数据集:1690张VOC+YOLO双格式使用指南 简介这份资源是面向工业质检与计算机视觉方向的布料缺陷检测数据集适合从事表面缺陷识别、目标检测模型训练与算法验证的开发者、学生及研究人员使用可解决破洞与污渍两类常见布面瑕疵的样本获取与标注问题。压缩包共2000个文件以1690个VOC格式xml标注文件和310个txt文件为主xml用于记录目标框位置txt对应YOLO格式标注及类别说明整体约84.76MB图片统一为640x640分辨率。数据集共1690张jpg图像标注类别为Holes破洞与Stain污渍框数分别为1268和1196总框数2464其中约500张为原图其余为增强图片可提升模型泛化能力。目前已有67人学习下载。读者可直接获得VOC与YOLO双格式标注省去自行采集与标注成本快速投入训练与对比实验并借助增强样本验证模型在复杂布面场景下的鲁棒性。1. 布料缺陷破洞污渍检测数据集1690 张 VOCYOLO 双格式到底怎么用产线质检的朋友跟我吐槽过一件事花两周标了一批布面缺陷图训出来的模型在验证集上 mAP 挺好看一上机就疯狂误报把正常纹理的阴影全框成污渍。问题不在模型在数据集——他手里那份标注只给了 VOC 的 XML类别名一会儿写hole一会儿写Hole还有几十张图漏标了破洞。布料缺陷破洞污渍检测数据集这类资源价值从来不在「有多少张」而在「格式对不对、类别稳不稳、划分合不合理」。这份 1690 张、2 类别的 VOCYOLO 双格式包正好卡在一个很实用的规模上够训一个能跑通的基线又不至于让你在清洗上耗掉一周。它适合三类人刚入门缺陷检测想找个真实工业场景练手的、手里有产线数据但不知道怎么规范成 VOC/YOLO 的、以及想验证自己训练管线是否正确的。下面我按「先看懂数据、再跑通训练、最后避开坑」的顺序讲清楚。2. 拆开这个 7zVOC 与 YOLO 双格式的目录结构和字段含义拿到一个压缩包别急着解压完就丢进训练脚本。先搞清楚里面到底有什么这一步决定了后面 80% 的返工。2.1 VOC 格式的目录约定与 XML 字段Pascal VOC 是缺陷检测里最通用的交换格式之一它的目录结构几乎是行业默认约定VOCdevkit/ └── VOC2007/ ├── Annotations/ # 每张图一个同名 .xml ├── JPEGImages/ # 原图通常是 .jpg ├── ImageSets/ │ └── Main/ # train.txt / val.txt / test.txt └── SegmentationClass/ # 本数据集用不到可忽略Annotations里的每个 XML 描述一张图的全部目标核心字段如下字段含义布料缺陷场景注意点folder所属目录名一般写JPEGImages不影响训练filename图片文件名必须和 JPEGImages 里完全一致含扩展名size宽高和通道数宽高写错会导致框整体偏移object/name类别名两类缺陷的字符串必须全局统一object/bndboxxmin/ymin/xmax/ymax必须是整数且 xminxmax、yminymaxdifficult是否难样本布料褶皱遮挡处可标 1训练时可选择忽略两个类别在 XML 里就是object节点的重复出现。一张图里同时有破洞和污渍就有两个object块这是 VOC 天然支持多目标的地方别把它们合并成一个框。2.2 YOLO 格式的 txt 与类别索引映射YOLO 格式把每张图的标注压成一个同名.txt每行一个目标class_id x_center y_center width height四个坐标全部是归一化到 0~1 的浮点数相对的是图片自身宽高。这里最容易翻车的是class_id它是从 0 开始的整数索引必须和classes.txt或data.yaml里的顺序严格对应。VOC 里写的是字符串类别名YOLO 里写的是数字转换时一旦映射表写反破洞和污渍就互换了模型学出来的东西完全是错的。0 0.512 0.334 0.087 0.121 # 假设 0 是 hole 1 0.221 0.780 0.153 0.096 # 假设 1 是 stain2.3 1690 张、2 类别的规模意味着什么1690 张对缺陷检测来说属于「小但可用」的量级。按常见 8:1:1 划分训练集约 1350 张、验证集约 170 张、测试集约 170 张。两类缺陷如果分布均衡每类在训练集里有六七百个实例训一个 YOLOv8n 或 YOLOv8s 的基线是够的。但如果某一类只占两三百个实例就得考虑过采样或强增强。判断分布是否均衡解压后先跑一段统计脚本别凭感觉import os, glob from collections import Counter label_dir labels/train counter Counter() for txt in glob.glob(os.path.join(label_dir, *.txt)): with open(txt) as f: for line in f: if line.strip(): counter[line.split()[0]] 1 # 统计每个 class_id 的实例数 print(counter) # 例如 Counter({0: 720, 1: 610})这段脚本遍历训练集所有标签文件按行首的类别索引累加实例数。如果两个数字差距超过 3 倍就要在训练配置里对少数类做复制增强或者调低它的置信度阈值容忍度。参数上没什么可调的label_dir换成你的实际路径即可。3. 从 VOC 转 YOLO转换脚本、坐标归一化和三个边界坑双格式包虽然省了转换但你要往自己的管线里接或者要扩标新数据转换逻辑必须自己会写。这一章给一份能直接用的转换脚本并把坐标计算里最容易错的地方讲透。3.1 一份可复用的 VOC 转 YOLO 脚本import os import glob import xml.etree.ElementTree as ET # 类别名到索引的映射顺序必须和训练配置一致 CLASSES [hole, stain] CLASS_TO_ID {name: i for i, name in enumerate(CLASSES)} def convert(xml_path, out_dir, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASS_TO_ID: continue # 跳过未定义类别避免索引错乱 bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 裁剪到图像边界内防止越界坐标 xmin, ymin max(0, xmin), max(0, ymin) xmax, ymax min(img_w, xmax), min(img_h, ymax) # 归一化并转中心点格式 xc (xmin xmax) / 2.0 / img_w yc (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{CLASS_TO_ID[name]} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}) base os.path.splitext(os.path.basename(xml_path))[0] with open(os.path.join(out_dir, base .txt), w) as f: f.write(\n.join(lines)) for xml in glob.glob(Annotations/*.xml): # 宽高建议从 XML 的 size 字段读这里演示用固定值 convert(xml, labels, img_w640, img_h640)逻辑上分四步解析 XML、按类别名查索引、把绝对坐标裁剪到图像范围内、归一化并转成中心点加宽高。参数说明CLASSES的顺序就是最终class_id的来源改这里等于改标签语义img_w/img_h最好从 XML 的size节点动态读取写死只适合所有图尺寸一致的场景:.6f保留六位小数是 YOLO 官方推荐的精度太少会累积误差。3.2 坐标归一化的三个边界坑第一个坑是坐标越界。标注员手抖把 xmax 标成 700 而图宽只有 640归一化后 w 会大于 1训练时框会飞出画面。脚本里的min/max裁剪就是防这个。第二个坑是零宽零高框。xmin 等于 xmax 时 w 为 0YOLO 在计算损失时会产生 NaN。转换后加一道校验把 w 或 h 小于 0.001 的行直接丢弃。第三个坑是图片尺寸和 XML 记录不一致。有些数据在标注后被统一缩放XML 里还是旧尺寸这时归一化基准就错了。稳妥做法是转换时用 PIL 重新读一遍真实图片尺寸而不是信 XMLfrom PIL import Image with Image.open(img_path) as im: img_w, img_h im.size # 以真实尺寸为准3.3 转换后必须做的两项校验转换完别直接开训先做两项检查。一是数量对齐Annotations的 XML 数、JPEGImages的图片数、生成的 txt 数三者应该一致缺一个都说明有图没标或标了没图。二是可视化抽检随机抽 20 张把 YOLO 框画回图上肉眼看一遍重点看破洞和污渍有没有互换、框有没有整体偏移。这一步花十分钟能省掉一次完整的错误训练。# 数量对齐快速检查 ls Annotations/*.xml | wc -l ls JPEGImages/*.jpg | wc -l ls labels/*.txt | wc -l三个数字对不上时用comm或 Python 求差集找出缺失的文件名通常是标注中途中断留下的孤儿文件。4. 用这份数据集训一个 YOLO 基线配置、命令与指标解读数据理顺了接下来跑通训练。这一章给一份能直接抄的 YOLOv8 配置和命令并说清楚每个参数为什么这么设。4.1 data.yaml 的写法与路径陷阱path: /data/fabric_defect # 数据集根目录 train: images/train val: images/val test: images/test nc: 2 names: 0: hole 1: stainpath是根目录train/val/test是相对它的子路径。最常见的翻车是路径写成绝对路径后换机器就失效或者names的顺序和转换时的CLASSES不一致。记住一条names里的索引就是标签文件里的class_id两边必须逐字对应。4.2 训练命令与关键参数yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ patience30 \ augmentTrue \ projectruns/fabric \ namebaseline参数逐个说model选yolov8s是因为 1690 张的规模用 nano 容易欠拟合、用 large 容易过拟合s 是甜点epochs150配合patience3030 轮验证指标不涨就早停省时间imgsz640是默认值如果布面缺陷很小比如针尖大的破洞可以提到 960 或 1280代价是显存和速度lr00.01是 SGD 的常见起点用 AdamW 的话降到 0.001augmentTrue开启内置增强对小数据集很关键。4.3 看哪些指标、阈值怎么定训练日志里重点盯三个mAP50、mAP50-95和每类的precision/recall。缺陷检测里 recall 往往比 precision 更重要——漏检一个破洞流到客户手里比多报几个让质检员复核代价大得多。所以定阈值时先看 recall 曲线把置信度阈值压到 recall 能到 0.95 的位置再回头看 precision 能不能接受。验证集上的混淆矩阵也要看。如果破洞和污渍互相误判严重说明两类在纹理上太像要么加更多区分性样本要么在标注规范里把边界定义写清楚比如污渍是否包含渗色边缘。5. 布料缺陷检测的避坑清单从标注到上线的五条血泪经验这一章是我自己踩过和看别人踩过的坑按「现象 → 原因 → 解决」写每条都对应这份数据集的实际使用。现象训练 loss 正常下降但验证 mAP 一直是 0。原因data.yaml里names的顺序和标签里的class_id对不上或者路径写错导致验证集根本没加载到图。 解决先跑yolo detect val单独验证看它报告的图片数量对不对再抽一张图可视化标签确认类别索引没错位。现象模型把布面正常纹理的阴影大量框成污渍。原因训练集里污渍样本的背景太单一模型学到了「暗色区域污渍」这种捷径而不是真正的污渍特征。 解决补充不同光照、不同布料的负样本训练时开启mosaic和hsv增强让模型见到更多背景变化。现象小破洞漏检严重大污渍框得很准。原因小目标在 640 分辨率下特征太少下采样几次后就没了。 解决把imgsz提到 960 以上或者在数据里对小目标做复制粘贴增强YOLOv8 的 P2 层对小目标有帮助可以换带 P2 的模型配置。现象同一张图里相邻的两个破洞被合并成一个框。原因标注时两个目标挨得太近或者 NMS 的 IoU 阈值设得太低把两个框合并了。 解决标注阶段就要求相邻目标分开标推理时把iou阈值从默认 0.7 调到 0.5 左右减少合并。现象本地验证很好部署到产线相机上效果崩了。原因训练图和产线相机的分辨率、光照、镜头畸变不一致域偏移严重。 解决拿产线相机实拍几百张哪怕只标一部分混进训练集做微调推理前做和训练一致的预处理缩放方式、归一化参数。6. 把 1690 张用出 5000 张的效果小数据集的增强与半自动标注技巧1690 张训一个基线够用但想真正上产线样本量往往是瓶颈。这一章讲两个我常用的放大手段都是在这类布料缺陷数据上验证过的。第一个是离线增强扩充。YOLO 内置的在线增强每轮随机变但有些变换它不做比如针对布料的纹理级增强。我会用 Albumentations 做一批离线增强图重点加GridDistortion模拟布料拉伸、RandomBrightnessContrast模拟光照波动和MotionBlur模拟产线相机运动。注意增强只对训练集做验证集保持原样否则指标虚高。import albumentations as A import cv2 transform A.Compose([ A.GridDistortion(num_steps5, distort_limit0.3, p0.5), A.RandomBrightnessContrast(brightness_limit0.2, contrast_limit0.2, p0.7), A.MotionBlur(blur_limit5, p0.3), ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_ids])) img cv2.imread(sample.jpg) with open(sample.txt) as f: boxes [list(map(float, l.split())) for l in f if l.strip()] bboxes [b[1:] for b in boxes] class_ids [int(b[0]) for b in boxes] out transform(imageimg, bboxesbboxes, class_idsclass_ids) # out[image] 和 out[bboxes] 就是增强后的图和框关键参数formatyolo告诉 Albumentations 框是归一化中心点格式它会自动同步变换bbox_params里的label_fields用来把类别索引和框绑定避免增强后类别丢失。增强倍数建议控制在 2~3 倍太多会让模型见过多合成样本而偏离真实分布。第二个是半自动标注。当你有一批新拍的未标注图先用训好的基线模型跑推理导出预测框作为预标注再人工修正。这样每张图的标注时间能从几分钟降到几十秒。流程是yolo detect predict导出带框的 txt写个脚本转回 VOC XML 或直接进标注工具人工只改错的、补漏的。这里有个习惯我坚持了很多年预标注的置信度阈值设高一点比如 0.5宁可漏标让人补也不要低置信度的错框干扰标注员判断。半自动标注省的是时间但校验环节一步都不能省否则错误会一代代传下去。最后说个验证技巧每次改完数据或增强策略别只看 mAP固定抽同一批 30 张难样本图把新旧模型的预测并排看。指标涨了但难样本没改善说明涨的是简单样本的分对产线没意义。这个习惯帮我避开了好几次「指标好看、上线翻车」的循环。希望帮到你。本文还有配套的精品资源点击获取