
简介面向工业缺陷检测、布匹缺陷识别与智能质检等实际项目这份数据集提供了800张真实布匹图像缺陷类别包含“损坏”和“污渍”两种常见瑕疵可支撑目标检测模型的训练、验证与效果评估。每张图像都附有VOCxml与YOLOtxt两种格式的标注文件兼容主流检测框架用户无需额外转换即可直接开始训练能显著降低数据预处理成本。压缩包共2401个文件其中jpg图片800个、xml标签800个、txt标签801个含类别说明文件整体大小约988MB文件组织规整便于按类别和序号检索。现有983人学习下载数据标注精确且经过项目实践校验算法拟合不错质量可靠适合算法工程师、研究人员及高校学生用于布匹瑕疵检测方案开发、模型调优和实验验证。整体数据在工业视觉场景中具备直接可用性配合完善的标签体系与文件结构可有效支撑布匹瑕疵检测算法的落地与迭代。1. 布匹缺陷检测数据集800张从voc和yolo标签出发能跑通yolo落地流程吗如果你在找布匹缺陷检测数据集八成是卡在工业质检这条路上公开的目标检测数据集大多是行人、车辆、日常物体放到织布车间里背景纹理一变模型直接废掉。标题这套800张的布匹缺陷检测数据集包含损坏、污渍两类缺陷同时给出voc与yolo格式标签刚好覆盖「数据准备→训练→验证」最费时间的环节。适合想快速验证yolo在纺织表面缺陷上效果的新手也适合评估工业小样本项目可行性的团队。先别急着训练把两种标签格式吃透后面能少走很多弯路。2. 拆解voc与yolo标签目录结构、坐标定义与缺陷标注画像拿到数据集的第一件事不是训练而是搞清楚标签格式到底存了什么。不少人在这一步翻车看着几百个xml觉得稳了结果转换后标签全错位训练两小时才发现心态直接崩。工业缺陷数据集通常长这样images目录放原图Annotations目录放voc的xml标注labels目录放yolo的txt标注。标题里提到的双格式指的就是Annotations和labels两套标注同时存在。先用文本编辑器打开一个xml看看里面到底存了什么。2.1 voc标签的xml结构真正起作用的字段只有这几个典型的voc单张标注长这样annotation folderimages/folder filenamefabric_0123.jpg/filename size width1920/width height1080/height depth3/depth /size object namedamage/name difficult0/difficult bndbox xmin521/xmin ymin337/ymin xmax884/xmax ymax712/ymax /bndbox /object object namestain/name difficult0/difficult bndbox xmin1200/xmin ymin540/ymin xmax1500/xmax ymax720/ymax /bndbox /object /annotation转换脚本真正用到的字段只有四个filename、size.width、size.height、object里的name和bndbox。folder和path不影响训练pose、truncated这些字段在voc检测里基本是历史遗留。difficult要留意voc时代用它标难例yolo训练里一般直接丢掉后面转换脚本会处理。布匹缺陷里同一张图出现多个object是常态一处破洞旁边可能跟着一处油污读取时用findall(object)而不是find(object)。拿到数据集先抽查三个xml确认三件事类名是damage、stain还是中文拼音缩写所有filename是否和images目录下的图片能对上size里的宽高和实际图片尺寸是否一致。这三项任何一项有问题后面训练全白跑。2.2 yolo标签的txt格式归一化坐标是怎么算出来的yolo格式的标签是纯文本每行一个目标和上面那张xml对应的txt内容是0 0.365885 0.485648 0.189062 0.347222 1 0.703125 0.583333 0.156250 0.166667从左到右五个值分别是class_id、归一化中心x、归一化中心y、归一化宽、归一化高。class_id从0开始和xml里的字符串类名不是一回事这是后续最容易错位的地方。归一化公式是固定的中心x等于(xmin xmax) / 2 / width宽等于(xmax - xmin) / widthy和height同理。上面第一行对应damage框(521884)/2/19200.365885(884-521)/19200.189062第二行对应stain框数值都能对上。yolo训练时把txt和图片按文件名匹配一张图对应一个txt。没有目标的图也要生成空txt空文件在yolo里代表负样本缺失txt则会被当成标签丢失处理训练时会有警告。这个细节在布匹缺陷场景里很关键因为实际产线上大量布料是正常的纯缺陷数据集训练出来的模型容易误报后面会专门说。2.3 统计标签分布宽高比和类别数量决定训练策略在动模型之前先把整个数据集的标签统计一遍。用这个脚本直接跑import glob from collections import Counter import xml.etree.ElementTree as ET xml_list glob.glob(Annotations/*.xml) cls_counter Counter() shapes {wide: 0, square: 0, tall: 0} total_boxes 0 for xml_path in xml_list: tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w float(size.find(width).text) img_h float(size.find(height).text) for obj in root.findall(object): cls_name obj.find(name).text cls_counter[cls_name] 1 box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) bw xmax - xmin bh ymax - ymin if bw 0 or bh 0: continue total_boxes 1 ratio bw / bh if ratio 3: shapes[wide] 1 elif ratio 1/3: shapes[tall] 1 else: shapes[square] 1 print(类别数量:, dict(cls_counter)) print(标注框总数:, total_boxes) print(宽高比分布:, shapes)运行前确认xml路径目录名不一致就改glob参数。脚本输出三类信息类别数量分布、总框数、宽高比分布。布匹缺陷里如果wide或tall占比很高说明存在大量抽丝、断纱、撕裂这类细长目标后面训练imgsz和图像切片策略都要跟着调整。如果两类数量差三倍以上就存在类别不平衡训练时要考虑要不要给少样本类加权重。3. 把voc标注转成yolo格式转换脚本、划分与边界坑标题说数据集同时附了voc和yolo标签但实际项目里你经常只拿到其中一种格式尤其是自己补充数据时新标注基本都是voc。所以转换脚本是绕不开的工具。这里给一套完整的转换加划分流程可以直接抄。3.1 转换脚本从xml解析到txt落盘的完整实现import os import glob import xml.etree.ElementTree as ET # 类别映射必须和后续 data.yaml 的 names 顺序完全一致 CLASS_MAP {damage: 0, stain: 1} xml_dir Annotations img_dir images label_dir labels os.makedirs(label_dir, exist_okTrue) xml_list glob.glob(os.path.join(xml_dir, *.xml)) for xml_path in xml_list: tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w float(size.find(width).text) img_h float(size.find(height).text) filename root.find(filename).text stem os.path.splitext(filename)[0] txt_path os.path.join(label_dir, stem .txt) lines [] for obj in root.findall(object): if obj.find(difficult) is not None and obj.find(difficult).text 1: continue cls_name obj.find(name).text if cls_name not in CLASS_MAP: continue box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) xmin max(0.0, min(xmin, img_w)) ymin max(0.0, min(ymin, img_h)) xmax max(0.0, min(xmax, img_w)) ymax max(0.0, min(ymax, img_h)) if xmax xmin or ymax ymin: continue cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h bw (xmax - xmin) / img_w bh (ymax - ymin) / img_h lines.append(f{CLASS_MAP[cls_name]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines))脚本逻辑很直接遍历xml读图片宽高和每个object的坐标换算成归一化值后写入同名txt。difficult1的框直接跳过这类难例框在yolo训练里通常弊大于利。坐标越界只夹紧到图片边界不做缩放因为少量越界是标注软件手滑夹紧对训练影响不大如果某个框越界几十像素说明标注本身错了应该回去改xml而不是硬转。输出保留6位小数对归一化坐标来说精度足够。提示CLASS_MAP的顺序会直接决定模型输出的类别顺序。转换、训练yaml、推理代码三处必须用同一个映射单独改任何一处都会导致类别错位。3.2 类别id映射一个映射文件管到底voc里的类名是字符串yolo只认整数id。最简单的做法是硬编码一个CLASS_MAP字典但更稳妥的是把这个映射单独存成一个json或yaml文件让转换脚本、训练配置、推理代码都读同一个文件。常见做法是把映射写在data.yaml里转换脚本里改成读这个yaml。布匹缺陷数据集的实际问题是damage和stain的边界经常模糊破损边缘发黑和深色污渍在视觉上接近。如果标注人员把同一块区域在不同图上标成不同类名转换脚本不会报错但模型会学到互相矛盾的监督信号。建议转换前先统计name字段到底出现了哪些取值有没有damaged、stains这类拼写不一致的情况统一之后再映射。3.3 train/val划分按图片切开并保持目录同步转换完成后做数据划分。800张图我一般按8:2切训练集640张、验证集160张160张足够看出训练趋势。划分要按图片走不能只切xml或只切txt否则训练集和验证集会互相缺标签。import os import random import shutil random.seed(42) image_dir images label_dir labels train_ratio 0.8 imgs [f for f in os.listdir(image_dir) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(imgs) split int(len(imgs) * train_ratio) train_imgs imgs[:split] val_imgs imgs[split:] for sub in [images/train, images/val, labels/train, labels/val]: os.makedirs(sub, exist_okTrue) def move_files(imgs, target_img, target_label): for img in imgs: stem os.path.splitext(img)[0] shutil.copy(os.path.join(image_dir, img), os.path.join(target_img, img)) txt stem .txt src_txt os.path.join(label_dir, txt) if os.path.exists(src_txt): shutil.copy(src_txt, os.path.join(target_label, txt)) else: print(missing label:, img) move_files(train_imgs, images/train, labels/train) move_files(val_imgs, images/val, labels/val)用shutil.copy而不是os.rename保留原始数据集这是你的后悔药。random.seed(42)固定随机顺序保证每次划分结果一致。missing label打印出来的是没有对应txt的图这些图要么是正常样本没有目标要么是标签丢失。前者可以留后者必须修。3.4 转换期边界坑越界、difficult、空txt、文件名大小写转换期间最常见的四个坑每个都能让训练悄悄变脏。坐标越界标注框比图片宽一两像素是常态脚本里已经做了夹紧但如果大量框越界优先怀疑标注软件导出设置。difficult字段有的数据集把所有模糊难例都标成difficult1如果不跳过模型会花大量精力拟合这些低质量标注跳过的话这类缺陷样本直接没了需要评估占比再决定。空txt没有目标的图片必须生成空txt很多新手漏掉导致yolo训练时当成标签缺失直接跳过这批图负样本信息全丢。文件名大小写xml里的filename写成Fabric_1.JPG磁盘上实际是fabric_1.jpgLinux下训练直接找不到图。转换前统一小写或统一大小写省去后面一堆路径报错。4. 用yolov8训练自己的布匹缺陷检测数据集目录结构、训练配置与命令标签问题清理干净后进入训练环节。yolov8训练自己的数据集是这套流程里最成熟的部分但工业小数据集的关键不在网络结构而在参数选择。800张图训练yolov8x和yolov8n的差距是大模型过拟合更快小模型反而更容易收敛出一个能看的baseline。4.1 数据集yaml配置目录结构、类别顺序与ultralytics的labels推导yolo训练需要一份数据描述文件放在数据集根目录下内容如下# data.yaml path: /your_path/布匹缺陷数据集 train: images/train val: images/val nc: 2 names: 0: damage 1: stainpath建议写绝对路径写相对路径时一定要确认当前工作目录。train和val只需要写images下的子目录ultralytics会自动在对应目录下找labels推导规则是把images替换成labels。如果标签目录不叫labels或结构不同训练时会提示找不到标签先查目录结构而不是怀疑代码。names顺序必须和第3章CLASS_MAP完全一致这是整条链路里最容易翻车的一环。4.2 训练命令与关键参数为什么小数据集用yolov8n而不是大模型环境配好之后一条命令启动训练yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs200 \ imgsz640 \ batch16 \ seed42 \ patience30 \ close_mosaic10 \ device0modelyolov8n.pt用官方预训练权重做初始化不是从零训练。从零训练在800张图上很难收敛预训练权重能直接继承通用特征。yolov8n是nano版本参数最少对这个小数据集来说容量刚好一上来用yolov8x只会更早过拟合。epochs200配合patience30验证指标连续30轮不涨就自动停小数据集通常跑不到200轮。batch16在常见显卡上能跑动nano模型显存不够就降到8但不要再低了batch太小会导致BN层的统计量不稳定yolo训练中bn崩溃大多数是batch过小加网络太深导致的。close_mosaic10让最后10个epoch关闭mosaic增强mosaic拼图对细长缺陷不友好后期关掉能让模型适应真实分布。训练前先跑一条预测命令确认环境畅通比如yolo detect predict modelyolov8n.pt sourcetest.jpg能出结果再开train避免训练到一半才发现cuda和torch版本对不上。4.3 训练日志怎么看收敛性快速判断训练结束后打开runs/detect/train目录下的results.png重点看三列指标。判断标准用下面这张表指标正常表现异常表现train/box_loss稳步下降后趋平震荡不降先查标签val/box_loss和train同趋势差距小下降后反弹过拟合mAP50逐渐爬升到0.6以上反复横跳验证集太小或标签乱mAP具体数值取决于缺陷和背景的对比度污渍这种深色块目标的mAP50通常会高于细小的破损。如果val/box_loss在第100轮开始反弹而train/box_loss还在降说明模型开始记住训练集背景纹理直接取best.pt而不是last.pt。如果mAP50全程锯齿状波动先别调超参大概率是某张验证图标签错位回去做可视化检查。5. 布匹缺陷数据集训练避坑标签错位、细长目标、过拟合与验证集划分下面这几条是从标注转换到训练收尾最容易踩的坑每一条都是能复现的血泪经验按「现象→原因→解决」写清楚遇到对应问题直接查。5.1 类别错位voc里的字符串name不等于yolo的数字id现象训练全程不报错但训练完跑预测污渍全部识别成损坏或者混淆矩阵里stain那一行几乎全是damage。原因有人写转换脚本时按xml里第一次出现的顺序给类名编号但训练yaml里names是按另一个顺序写的两边映射对不上。这个问题在布匹缺陷这类两分类数据集上特别隐蔽因为模型loss照样下降很多人到部署阶段才发现。解决转换、训练、推理三处统一用一个CLASS_MAP或一个data.yaml转换后随机挑5张图把预测框和真实框画出来人工确认类别。确认这一步别省几百张图抽5张花不了两分钟。5.2 复合缺陷标签打架同一块区域标了两类现象训练损失曲线下降很慢验证时损坏和污渍互相误检尤其出现在破洞边缘带油污的图上。原因标注规范没定义清楚。同一块区域同时存在破损和污染时有的标注员标damage有的标stain有的两个都标模型收到互相矛盾的监督信号。解决从源头定规则。我的做法是同一区域只标主要缺陷破洞为主就标damage油污为主就标stain如果这类复合缺陷图数量够多干脆单独开一类complex让模型学三类而不是在两个类之间纠结。转换脚本可以做重叠框过滤但那是后处理治标不治本。5.3 细长缺陷测不到imgsz和图像切片的取舍现象验证集里抽丝、断纱几乎全漏检但污渍检出率正常。原因布匹的抽丝缺陷经常只有几个像素宽imgsz640下采样后特征直接消失污渍是块状目标不受影响。解决先看第2章统计脚本输出的宽高比分布如果wide或tall占比高优先把imgsz提到1280显存不够就做tiling把原图切成几块分别推理再合并结果。不要一上来就换注意力模块或改loss对布匹缺陷来说输入分辨率往往比模型结构更关键。5.4 验证集随机划分假象mAP虚高现象本地验证mAP不错拿到现场一段布料上跑全是误报。原因数据划分时用随机shuffle同一匹布的连续帧可能同时进训练集和验证集模型等于提前见过验证答案或者某个缺陷类型只在验证集出现训练集里压根没有。解决按图片名前缀分组划分如果图片名带批次号或日期以批次为单位切分保证同一布种、同一光照条件不跨集合。工业相机采集的数据天然自带相关性随机划分很多时候并不随机。5.5 小数据集过拟合预训练权重与增强策略现象train/box_loss降到接近0val/box_loss在第150轮后反弹mAP停滞不前。原因800张图对yolo来说属于小样本模型把训练集背景纹理一起记住了。解决先用yolov8n跑baseline不要在样本量不足时追求大模型epochs200配合patience30如果best.pt和last.pt差很多说明后半程都在过拟合直接用best.pt。有条件的额外收集一批正常布匹图作为负样本不标任何目标yolo空txt天然支持这种样本能显著降低现场误报。6. 训练完先别急着部署混淆矩阵和三件验证小事训练结束第一件事不是接生产线而是重新跑一遍验证把模型行为看清楚。一条命令生成全套验证图yolo detect val modelruns/detect/train/weights/best.pt datadata.yaml plotsTrueplotsTrue会重新生成confusion_matrix.png。看混淆矩阵时别纠结每行加起来是不是1yolo默认按行归一化总合不唯一是正常的重点看每一类真实缺陷被认成了谁。布匹缺陷里最常见的情况是damage被认成stain说明两类特征太接近标注规范要去重damage被认成background说明目标太小或对比度低优先提imgsz。第二件事是重训一次验证稳定性。训练命令里已经固定seed42换个seed再训一遍如果mAP50波动超过3个点说明800张图撑不起当前模型容量加数据比加模块更划算。第三件事是翻badcase图runs/detect/val目录下会存一批预测错误的样本一张一张看是标注问题还是模型问题这比盯loss曲线更直接。我现在的习惯是数据集到手先按这套流程走一遍统计、转换、可视化、跑baseline、翻badcase全部确认没问题之后才允许自己动网络结构。数据没洗干净之前改模型全是玄学。希望这次整理的几个验证习惯能帮到你。本文还有配套的精品资源点击获取