一份可直接训练的YOLO布匹瑕疵数据集:格式、划分与避坑指南
简介一套面向布匹质检场景的YOLO格式瑕疵检测数据集适合计算机视觉开发者、算法研究人员以及纺织行业质检人员使用。数据严格按YOLOv5目录保存训练集约550张图片及对应txt标注测试集约140张图片共定义46类瑕疵涵盖擦洞、跳花、油渍、线印、扎洞、毛粒等常见缺陷类别已写入classes文件下载后可直接投入yolov5训练或基于该基线做改进实验。包内共1413个文件其中706个jpg图像与706个txt标签一一对应另有1个json配置文件整体容量944.12MB结构规整免去自行划分数据集与格式转换的步骤。目前已有470人学习借助该数据集可快速搭建布匹缺陷自动检测模型用于产线质量监控、算法精度对比或YOLO系列改进研究。1. 布匹瑕疵检测数据集一份划分好的YOLO格式数据为什么值得用一卷布以每分钟几十米的速度过机质检员要在一瞬间判断某个斑点是不是瑕疵。这个岗位的疲劳度和漏检率正是YOLO这类目标检测算法切入工业质检的天然理由。可真正开始训练最卡人的往往不是模型结构而是数据网上的布匹瑕疵公开数据要么是VOC/COCO格式要么没有划分好的训练集更常见的是连类别清单都没有一份。这份标题里的数据集把两件脏活提前干完了——标注已经是YOLO的txt格式train/val/test分得清清楚楚class文件也单独给出。适合谁想用YOLO快速跑通布匹瑕疵检测、不想从整理标注开始的人。2. 拆解数据集结构images、labels、class文件与目录划分2.1 YOLO的目录约定一张图片对应一个同名txt拿到任何一份YOLO格式的数据集第一步不是急着训练而是把目录结构先摸清楚。常见组织方式是这样图片放在images下分train、val、test三个子目录标注txt放在labels下同样拆成三份。每张图片对应一个同名txt比如20230512_roll_001.jpg对应20230512_roll_001.txt。图片是jpg还是png无所谓但txt的名字必须和图片去掉后缀后的文件名完全一致否则训练时找不到标注整张图会被当成背景跳过。打开一个txt内容是这样的几行数字0 0.5172 0.6825 0.0831 0.0417 2 0.3158 0.2409 0.1204 0.0556 1 0.7843 0.5021 0.0628 0.0329每行五个数含义固定第一个数是类别ID从0开始后面依次是瑕疵框中心点的x坐标、y坐标、框宽、框高。最关键的是这四个值不是像素值而是相对图片宽高的归一化比例取值必须在0到1之间。YOLO从v5到v11训练数据格式都认这一套所以这份数据集以后做不同版本的对比实验也不用重新转换。归一化约定有两个直接好处。第一换输入分辨率不用改标注训练时无论缩放到640还是1024坐标都能直接参与运算第二模型输出的框本身就是0到1之间的比例坐标推理后乘以原图尺寸就能还原像素位置省掉一套坐标换算逻辑。2.2 class文件决定类别ID顺序错了全盘错位class文件通常就是纯文本一行一个类别名比如hole oil_stain warp_break这里有一个新手最容易忽略的细节txt标注里的类别ID数字就是class文件的行号从0开始计数。上面这个文件里hole是第0行所以所有破洞标注在txt里写0oil_stain是第1行统一写1warp_break是第2行统一写2。一旦你自己重写data.yaml时把names的顺序调换整个模型的输出类别就全部错位油污会被学到破洞上。拿到class文件后我习惯先把每个类别名对应到实际瑕疵照片上看一遍。布匹瑕疵的命名在不同工厂差异极大有的按工艺分破洞、断经、纬缩、油污、褶皱有的按颜色深浅分有的把飞花、竹节这类纱线瑕疵单独列出来。题目里提到的类别class文件其实就是这份映射表它决定了模型到底在学哪几个缺陷类型也直接决定训练配置文件里的nc参数。如果想快速确认每个类别的标注数量分布可以用下面这个脚本统计避免某个类在训练集里样本太少import os from collections import Counter def count_classes(labels_dir): counter Counter() for fname in os.listdir(labels_dir): if not fname.endswith(.txt): continue path os.path.join(labels_dir, fname) with open(path, r) as f: for line in f: line line.strip() if line: cls line.split()[0] counter[cls] 1 return counter # labels_dir 换成实际路径例如 labels/train print(count_classes(labels/train))脚本逻辑不复杂遍历指定目录下所有txt读取每一行的第一个字段也就是类别ID放进Counter里做累加。它能回答两个关键问题各类别样本是否均衡以及train/val/test里类别分布是否一致。如果某个瑕疵类别在训练集里有800个框验证集里只有2个那后续训练时这个类基本学不好。2.3 划分好的train/val/test为什么按布卷隔离比随机划分更可靠很多公开数据集只是把图片打了标注划分什么的不存在的。这份数据集既然把train/val/test分好了你需要先理解它到底按什么原则切分再决定能不能直接拿去训练。对于布匹瑕疵来说同一个布卷的连续帧在底纹、光照、瑕疵位置上高度相似。如果这些相似的帧被随机打散到train和val模型在训练时等于提前见过验证集的内容验证mAP会虚高。上了产线换一卷新布模型立刻暴露出真实水平。所以可靠的数据集划分应该按布卷或拍摄时间段隔离而不是简单地随机抽样。拿到划分后可以做一个快速体检。用下面的命令统计每个集合的图片数和标注数看在数量级上是否合理for split in train val test; do echo $split echo images: $(ls images/$split | wc -l) echo labels: $(ls labels/$split | wc -l) echo boxes: $(cat labels/$split/*.txt | wc -l) done这三行命令分别数出图片文件数、标注文件数和总框数。page一般train占70%到80%val和test各占10%到15%。框数和图片数如果出现明显失衡比如train图片2000张但框只有50个就要警惕是不是大量图片没有标注训练时会被全部当作背景造成严重的正负样本不平衡。3. 把VOC/COCO标注转换成YOLO格式转换脚本与四个边界坑3.1 坐标转换公式从像素框到归一化中心点如果拿到的布匹缺陷数据不是YOLO格式而是一堆VOC的xml或者COCO的json你需要先把坐标转换过来。VOC的xml里存的是xmin ymin xmax ymax单位是像素COCO存的是左上角x、左上角y、框宽、框高同样是像素。YOLO要的是相对图片宽高的归一化中心点坐标。转换公式是固定的四行x_center (xmin xmax) / 2 / img_width y_center (ymin ymax) / 2 / img_height w (xmax - xmin) / img_width h (ymax - ymin) / img_height分母必须用图片的实际宽高而不是框所在区域宽高。有的转换代码写成用像素绝对值除以固定imgsz这在训练时可能不报错但所有标注都会整体偏移导致检测框位置偏差。另外xmin和xmax读出来是字符串先用int()再参与计算否则Python里会做字符串拼接得到的结果全是错的。3.2 一个可复用的VOC转YOLO的Python脚本下面是一个可以直接跑通的转换脚本我平时处理VOC格式布匹数据就是拿它改的。它遍历一个目录下所有xml转成同名txt并自动跳过不在类别清单里的目标import os import xml.etree.ElementTree as ET def voc2yolo(xml_path, txt_path, class_names, img_width, img_height): tree ET.parse(xml_path) root tree.getroot() with open(txt_path, w) as out: for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue # 不在类别清单里的目标直接跳过 cls_id class_names.index(name) bndbox obj.find(bndbox) xmin int(float(bndbox.find(xmin).text)) ymin int(float(bndbox.find(ymin).text)) xmax int(float(bndbox.find(xmax).text)) ymax int(float(bndbox.find(ymax).text)) x_center (xmin xmax) / 2.0 / img_width y_center (ymin ymax) / 2.0 / img_height w (xmax - xmin) / img_width h (ymax - ymin) / img_height # 防止越界导致训练崩溃 x_center min(max(x_center, 0), 1) y_center min(max(y_center, 0), 1) w min(w, 1) h min(h, 1) out.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n) # 使用示例 class_names [hole, oil_stain, warp_break] img_width 1024 img_height 1024 for xml_file in os.listdir(voc_annotations): if xml_file.endswith(.xml): xml_path os.path.join(voc_annotations, xml_file) txt_path os.path.join(yolo_labels, xml_file.replace(.xml, .txt)) voc2yolo(xml_path, txt_path, class_names, img_width, img_height)脚本的逻辑分三段先解析xml拿到所有object节点然后对每个目标做类别名匹配并读取边界框坐标最后套用上面的公式完成归一化并写入txt。关键参数有两个class_names的顺序必须和将来data.yaml里的names保持一致img_width和img_height必须和图片真实尺寸一致否则坐标全部变形。实际使用中建议把voc_annotations和yolo_labels换成你自己的目录路径。如果图片尺寸不统一不要写死宽高在脚本里额外用PIL或cv2读取每张图片的实际尺寸这样最稳妥。3.3 越界框、空标注、类别错位、灰度图四个边界坑第一个坑是越界框。部分标注工具在人工画框时允许框超出图片边缘xmax会大于图片宽度导致归一化后的w超过1。YOLO在算锚框匹配时遇到这种值会行为异常轻则训练loss震荡重则直接崩溃。解决方式就是脚本里那三行clip操作把中心点和宽高全部限制在0到1之间。第二个坑是空标注。一张布匹图片没有任何瑕疵时xml里没有object节点输出txt是空文件。有些脚本遇到这种情况就不生成txt这是不行的。YOLO训练时如果图片没有对应txt会把它判定为非标注图片跳过导致实际参与训练的图片数和清单对不上。正确做法是仍然生成一个空txt表示这张图存在且没有目标。第三个坑是类别错位。xml里的标签名是holeclass_names列表里写的是hole看起来一样但如果class_names顺序和class文件顺序不一致生成的类别ID就对不上。比如class文件里hole在第2行而转换脚本的class_names把hole放第0行那txt里的0实际是warp_break。转换前先核对class文件这个步骤不能省。第四个坑是灰度图。工业相机采到的布匹图像经常是单通道灰度或者12bit深度图像直接喂给YOLO会在数据加载阶段报通道数错误。常见做法是用CV2统一转成三通道8bit顺带做一次归一化。转换代码里加一行img cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)再把深度图用cv2.convertScaleAbs转到8bit不过这步要放在坐标转换之前且转换后的宽高不能变。4. 用这份数据训练YOLOv8/v5data.yaml与关键参数怎么设4.1 data.yaml的组织方式path、train、val、names一个都不能少数据集目录确认没问题下一步就是写训练配置。YOLOv8训练自己的数据集统一靠一个data.yaml文件描述数据来源。最小可用配置长这样path: /data/fabric_defect train: images/train val: images/val test: images/test nc: 3 names: 0: hole 1: oil_stain 2: warp_breakpath字段是数据集根目录的绝对路径train、val、test是相对这个根目录的路径。这里的nc要和onesnames里的类别数严格一致写成3就表示模型输出三个类别。names的顺序必须和class文件一致这一点我在前面的章节反复强调过因为它直接决定了txt里数字ID的含义。有一个常见翻车点如果yaml里只写相对路径而不写pathYOLO会拿当前工作目录去拼一旦你在别的目录下执行训练命令就会报Dataset not found。所以我现在都习惯用绝对路径写死path省得每次换机器都要改。另外Windows用户的路径分隔符是反斜杠yaml解析容易出问题统一用正斜杠最稳妥。4.2 训练命令与超参imgsz、batch、epochs怎么定data.yaml就位后最简单的训练命令是yolo train datafabric.yaml modelyolov8s.pt epochs300 imgsz640 batch16 device0拆开看每个参数。modelyolov8s.pt表示从COCO预训练的yolov8s权重开始训练这是迁移学习的标准做法。有人问coco80是什么其实是指COCO数据集的80个类别这个预训练权重已经见过大量自然图像特征放到布匹瑕疵上能省下大量训练时间也更容易收敛。imgsz640是输入分辨率。布匹瑕疵里破洞、线头这类目标往往只有几十个像素640不一定够。我的经验是先把imgsz调到1024试一轮如果显存不够或者训练速度不可接受再退回736或896。这个参数对检测小目标的影响比换任何模型结构都直接。batch16要看显存来定显存只有8G就把batch降到8或4显存充足可以开到32或64。建议先跑一次看显存占用再决定batch大小。epochs300对工业瑕疵检测来说不算多配合早停机制模型通常能在150到200轮左右收敛到稳定水平。早停和自适应学习率都是YOLO的默认行为不需要额外配置。跑起来之后要盯的不只是训练loss。loss会随着轮次下降但更值得注意的是验证集上的mAP曲线。如果loss在降而mAP一直不动大概率是数据划分或标注本身出了问题先停下来检查数据不要盲目加轮次。4.3 布匹场景下的增强与损失函数参数mosaic、类别不平衡、CIoU布匹瑕疵检测和通用目标检测有个明显差异布面本身有纹理、有光泽、有周期性图案这些背景特征如果被增强策略放大模型很容易把正常的织纹当成瑕疵。YOLOv8默认开启mosaic增强把四张图拼成一张训练图对通用检测是好事但对布匹场景拼接处会产生假的纹理边界反而干扰模型。常见做法是把mosaic概率调低比如mosaic0.5甚至在数据增强里关闭它改成只靠旋转、平移、翻转。怎么调看验证效果如果训练中期mAP还在稳定上涨说明mosaic没有坏事保持默认如果val mAP在epoch 100之后反而开始下降优先怀疑增强策略过度。类别不平衡也是布匹瑕疵的常态。油污可能占60%的标注框破洞只占5%模型会倾向于把不确定的区域判成油污。解决思路有两个一是用训练脚本里默认的cls损失权重给稀有类别提高权重二是做简单的过采样把破洞样本复制几份混进训练集。YOLOv8的损失由box、cls、dfl三部分组成默认权重一般够用但如果发现稀有类别召回率特别低可以手动把cls权重从0.5提到0.7或1.0。损失函数本身在YOLOv8里默认是CIoU对大多数情况都适用。布匹瑕疵框有些是细长的比如断经这种横向条状缺陷长宽比极端此时可以试试SIoU或WIoU这类更关注几何关系的损失。结论是别一上来就换损失函数先用默认配置训一个baseline确认瓶颈在模型还是在数据再决定要不要动这些参数。5. 避坑布匹瑕疵检测数据集最常见的五个翻车现场5.1 训练loss很低验证mAP却上不去数据泄漏现象训练集上loss降得很漂亮准确率接近满分但val mAP一直在0.5以下徘徊检测出的框和真实标注对不上。原因数据划分没按布卷隔离。同一卷布的连续帧被随机分到train和val模型在训练阶段已经把val的底纹学进特征里真正跑验证时遇到没见过的布卷就崩。解决需要自行重新划分。按文件名的布卷ID或拍摄时间聚合把同一个布卷的图片全部分到同一个集合。可以写个脚本按文件名前缀分组再重新生成train/val/test目录务必重新转换标注路径。5.2 推理时把布面纹理当瑕疵标注边界没定清现象模型在褶皱、阴影、金属光泽区域输出一堆置信度0.5以上的框而真正的油污和破洞反而被漏掉。原因标注人员把布匹表面的正常编织纹理和光照反光也当成了目标。class文件里类名定义不清导致不同标注员对油污的理解不一致有的标了阴影有的没有。解决回看class文件给每个类写清楚定义边界。比如规定油污必须是从外界沾上的深色污渍面积小于一平方厘米纯色阴影不算。best做法是把定义和示例图贴在标注文档里然后重新过一遍标注数据删除那些模棱两可的框。5.3 破洞、线头等小目标漏检分辨率与下采样现象大瑕疵比如油污和褶皱基本能检测到但破洞、线头这类只有十几像素的小目标召回率不到50%。原因640的输入分辨率经过模型五层下采样后小目标的特征在最后几层特征图里只剩下几个像素丢失严重。解决先把imgsz提到1024这一步通常立竿见影如果显存不允许至少到896。还可以用小模型yolov8n的更高分辨率版本或者在推理时把原图切片成多块分块检测后合并结果这样不用改模型也能保小目标。5.4 测试集指标高换一块布就拉胯背景过拟合现象测试集mAP有0.8看似不错。一到工厂现场换了一卷不同底色或纤维密度的布检测效果直线下降。原因训练和测试数据来自同一个布卷或同一条产线模型学到的是这块布的纹理背景而不是瑕疵本身。布匹质检往往只采了几卷样本背景多样性不足。解决收集不同底色、不同编织密度的布样重新扩数据。如果条件有限可以先做数据增强模拟底色变化用hsv_h、hsv_s扰动和亮度抖动缓解背景过拟合但这只是亡羊补牢本质还需要真实多样性样本。5.5 class文件中文乱码或类别错位编码与顺序现象class.txt里直接写了中文类名训练时控制台报编码错误或者模型训练完了输出的类别名和对应关系全乱。原因Windows下文本文件默认可能是GBK编码YOLO加载yaml和names时统一按UTF-8读遇到GBK字符直接崩溃或乱码。解决用文本编辑器把class.txt另存为UTF-8无BOM格式。data.yaml里如果写了中文names同样要保持UTF-8。更稳妥的做法是class文件和names全用英文或拼音中文只在注释里解释避免跨平台编码问题。6. 验证与进阶用mAP、混淆矩阵和可视化检查瑕疵模型模型训练完成后第一件事不是急着导出部署而是用验证集做一次完整评估。跑以下命令yolo val modelruns/detect/train/weights/best.pt datafabric.yaml输出里主要看几个指标mAP50反映的是宽松IoU阈值下的整体水平布匹瑕疵检测至少要到0.85才算合格mAP50-95是严格阈值下的均值小瑕疵多的地方通常只有0.5到0.7Precision和Recall要在0.9左右否则说明误检和漏检没有平衡好。接下来打开训练输出目录里的混淆矩阵图confusion_matrix.png重点看哪些类别互相混淆。比如油污被误判成深色织纹破洞和线头分不清这些都是数据标注质量问题不是调参能解决的。看清楚之后再决定要不要合并类目、修正标注。可视化这一步不要只看训练时保存的图片我习惯单独挑十来张验证集里最难的图用训练好的权重跑一次推理肉眼检查检测框和置信度。框的位置准不准、有没有把纹理误检成瑕疵、置信度低于0.5的真实缺陷是不是完全没框出来这些只看指标看不出来。一切正常后就可以导出ONNX部署到产线侧。命令很简单yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640导出后可以用ONNX Runtime在Jetson或者工控机上跑推理。如果瑕疵类别在视觉上高度重叠比如油污包含了深浅程度不同的大量样本纯目标检测会频繁漏检可以换YOLOv8的实例分割权重做像素级分割把瑕疵轮廓标出来布匹质检的价值更高。回到开头说的那份数据集训练出合格模型的逻辑其实不复杂先把目录和class文件理顺再用划分严谨的数据训练最后靠验证集和可视化把模型钉死。我有一个一直保留的习惯任何数据集到手先把val里最难的那几张图单独复制出来训练完成后第一件事就是拿这几张图试推理。这个习惯帮我拦下了很多次测试集指标很好、现场全崩的翻车。希望帮到你。本文还有配套的精品资源点击获取