ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

毛巾缺陷检测实战:VOC标签转YOLO格式并训练YOLOv8

毛巾缺陷检测实战:VOC标签转YOLO格式并训练YOLOv8 简介面向毛巾织物外观质检与毕业设计场景的缺陷检测数据集内含435张已标注缺陷图片并配套VOC格式xml与YOLO格式txt两种标签可直接接入主流目标检测框架训练。全包共1307个文件由436个txt标签、436个xml标签和435张jpg原图组成压缩包大小约11.72MB目录简洁按文件名一一对应便于批量读取和划分训练集。目前已有420人学习下载适合作为毕设缺陷检测实验、模型对比或数据增强练习的基准数据。若需扩充样本可基于该批图片进行旋转、亮度、裁剪等增强处理描述中提到的增强脚本也可按页面说明留言或私信获取。对需要快速获得完整标注集、省去手工标注环节的读者这套素材覆盖了从数据准备到格式转换的常见需求能帮助把重心放在算法设计与结果分析上。1. 毛巾缺陷检测数据集435张标注图直接喂给YOLO做纺织品缺陷检测的都知道找数据集比训练模型痛苦得多。公开的织物数据集要么背景单一要么标注格式七零八落拿回来还得花两周清洗。这份毛巾缺陷检测数据集一共435张图片每张图配套VOC格式的XML标签和YOLO格式的TXT标签省掉了最磨人的标注环节。图片按que(编号).jpg命名编号规则统一标签一一对应可以直接灌进YOLOv5、YOLOv8等主流检测框架跑训练。对于正在做缺陷检测相关毕业设计、或者想拿真实工业场景练手目标检测的开发者来说这套数据足够支撑一次完整的训练流程。数据量不大但胜在格式干净配合增强脚本可以撑起一个像样的项目。2. 从VOC到YOLO标签格式解构与转换脚本2.1 XML标签结构先搞清楚VOC里存了什么VOC格式是目标检测最通用的标注格式LabelImg默认导出的就是这种结构。数据集里的435个XML文件虽然数量多但结构完全统一打开任意一个文件核心信息就几块folder记录图片所在目录filename是对应图片名size里的width和height是图片的真实宽高object块每出现一次就代表一个标注目标里面嵌套着类别名name和边界框bndbox。边界框bndbox里的xmin、ymin是目标左上角的像素坐标xmax、ymax是右下角坐标全部是绝对值单位是像素。这个细节很关键后面转YOLO格式时要做归一化分母用的就是size里的宽和高。如果XML里写的尺寸和图片实际尺寸对不上转换出来的坐标全是偏的。annotation folderque/folder filenameque(414).jpg/filename size width640/width height640/height depth3/depth /size object namedefect/name bndbox xmin86/xmin ymin121/ymin xmax342/xmax ymax289/ymax /bndbox /object /annotation解析XML时别用正则去抓数字虽然正则也能提取出坐标值但XML里还混着size、folder这些无关数字一旦结构里多一个节点抓出来的值就全错位了。用ElementTree按标签路径逐层读是最稳的方案路径直接写进find方法里少写两行循环也少一个出错点。import xml.etree.ElementTree as ET tree ET.parse(que(414).xml) root tree.getroot() for obj in root.findall(object): name obj.find(name).text xmin int(obj.find(bndbox/xmin).text) ymin int(obj.find(bndbox/ymin).text) xmax int(obj.find(bndbox/xmax).text) ymax int(obj.find(bndbox/ymax).text) print(name, xmin, ymin, xmax, ymax)obj.find(bndbox/xmin)这种路径写法一次性定位到深层节点不需要连续find两次。取出来的值要记得用int()强转XML读出来全是字符串后面做归一化除法时字符串和浮点数直接运算会抛TypeError这一步踩的人不少。2.2 转换脚本VOC转YOLO的完整实现YOLO格式的标签是纯文本文件每行代表一个目标格式固定为五个值类别ID、归一化中心点x、归一化中心点y、归一化宽、归一化高。注意中心点坐标和宽高全部要除以图片的宽和高宽除以宽、高除以高不能交叉除。图片如果不是正方形交叉除会导致框整体偏移训练时损失函数看起来正常但预测框全打在错误位置。import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_path, class_names): 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): name obj.find(name).text if name not in class_names: continue class_id class_names.index(name) xmin int(obj.find(bndbox/xmin).text) ymin int(obj.find(bndbox/ymin).text) xmax int(obj.find(bndbox/xmax).text) ymax int(obj.find(bndbox/ymax).text) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines)) class_names [defect] xml_dir VOC/Annotations txt_dir VOC/labels os.makedirs(txt_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): voc_to_yolo( os.path.join(xml_dir, xml_file), os.path.join(txt_dir, xml_file.replace(.xml, .txt)), class_names )这个脚本里class_names列表的顺序直接决定类别ID的编号如果以后要加类别只能在列表尾部追加不能插在中间否则已经生成的TXT文件里ID全部失效。输出坐标保留6位小数YOLO训练读取时浮点误差完全可以忽略。os.makedirs加了exist_okTrue目标目录存在时不会报错不存在时自动创建不用每次手动mkdir。毛巾缺陷检测里常见的类别可能不止一种破洞、污渍、跳纱、毛边这些在真实质检场景会分开标。这份数据集的标签以实际标注为准如果你的项目跑起来发现只有defect一个类想要细分可以手动改XML里的name字段再重新执行一次转换。2.3 转换中的边界坑尺寸不一致、越界框与中文类名格式转换这个环节看起来简单实际跑一遍数据会发现各种幺蛾子。我拆数据集时遇到了四类问题基本覆盖了VOC转YOLO的大部分坑。第一个坑是XML里写的size和图片实际尺寸对不上。标注工具偶尔会把尺寸信息写错尤其是标注前压缩过图片的情况。我习惯在转换脚本开头用PIL重新读一遍图片宽高XML里的size只当参考不信它。from PIL import Image img Image.open(img_path) actual_w, actual_h img.size第二个坑是标注框越界。有些标注员手一抖把框拖出了图片边界xmin是负值或者xmax大于图片宽。归一化后坐标会出现负数或大于1的值YOLO训练时边框回归会不稳定。遇到这种标注我一般直接裁剪掉不保留这种脏数据。第三个坑是中文类别名。YOLO训练不认中文class_names列表里出现过中文转换脚本虽然能正常输出TXT但训练时data.yaml里的names字段会解析报错。统一用英文或拼音比如defect、hole、stain这种。第四个坑是XML文件里有重复标注。同一张图里同一个缺陷被框了两遍转换后TXT里会出现两个几乎重合的框。这个问题肉眼很难发现我后来写了个检查脚本统计每个TXT文件里是否存在IoU超过0.9的框对有的话自动删掉一个。提示转换完成后一定要抽检别直接开训练。最省事的方法是写个可视化脚本把TXT坐标还原成矩形画在图片上肉眼过一遍就能发现问题。3. 在YOLOv8上训练毛巾缺陷检测从目录到推理3.1 数据集目录结构train/val划分的规范做法拿到数据集的第一件事不是改代码而是把目录结构整理成YOLO要求的格式。YOLOv8默认的目录约定是images下分train和val两个子目录labels目录结构必须和images一一对应图片和标签文件名相同、后缀不同。435张图按8:2比例划分训练集里放348张验证集放87张划分时要随机但要修好随机种子不然每次跑出来的验证集都不一样没法横向对比实验。dataset/ ├── images/ │ ├── train/ │ │ ├── que(1).jpg │ │ └── ... │ └── val/ │ ├── que(10).jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── que(1).txt │ │ └── ... │ └── val/ │ ├── que(10).txt │ └── ... └── data.yaml划分脚本我通常用shutil直接把文件名列表打乱后搬运不用scikit-learn的train_test_split少一个依赖。分割完以后记得打印两边的图片数量做校验。import os import random import shutil random.seed(42) image_dir VOC/images train_dir dataset/images/train val_dir dataset/images/val all_images os.listdir(image_dir) random.shuffle(all_images) val_count int(len(all_images) * 0.2) for i, img_name in enumerate(all_images): dst_dir val_dir if i val_count else train_dir shutil.copy(os.path.join(image_dir, img_name), dst_dir)随机种子固定成42保证每次划分结果一致。验证集不要选太少87张对于缺陷检测来说已经是下限了再少的话评估指标波动会很大一个误报就能让mAP掉两三个点。3.2 data.yaml配置与模型选择data.yaml是YOLO训练的数据配置文件路径、类别数、类别名全在这里。train和val指向图片目录YOLO会自动去同级的labels目录找标签不需要单独写标签路径。train: dataset/images/train val: dataset/images/val nc: 1 names: [defect]nc和names里的类别数必须和TXT标签里的类别ID对齐。如果你转换脚本里class_names写的是[defect]data.yaml这里的names也必须是[defect]两边写法不一致会导致YOLO训练时类别索引混乱损失函数显示正常但预测出来的框全部是错的。模型选择上435张图属于典型的小数据集场景。yolov8n参数量最小最容易收敛我用它作为首选。如果算力允许可以试yolov8s效果会好一些但过拟合风险也更高。yolov8m以上的版本别碰这个数据量喂不饱大模型训练出来的效果多半不如小模型。注意下yolov8n.pt预训练权重首次运行时需要联网下载建议提前把权重文件准备好省得训练中途卡在下载环节。3.3 训练命令与超参数设置YOLOv8的训练命令用CLI就能跑不需要写Python脚本。最基本的训练指令是yolo detect train datadataset/data.yaml modelyolov8n.pt epochs200 imgsz640 batch16 patience30 device0各参数含义epochs200是最大训练轮数小数据集上通常100到200轮之间就能收敛imgsz640是训练时缩放的输入尺寸毛巾纹理缺陷的细节比较多别降到416小目标会丢失batch16取决于显存大小6GB显存跑batch16差不多是极限patience30是早停参数连续30轮验证集指标不提升就自动停止device0指定用第一张GPU。训练过程中最需要盯的是loss曲线。正常情况训练损失和验证损失都会持续下降然后趋于平缓如果验证损失先降后升说明开始过拟合了这时候该考虑数据增强或减小模型容量。3.4 训练结果怎么看混淆矩阵与PR曲线训练结束后YOLOv8会在run目录下生成result.csv、混淆矩阵、PR曲线等文件。对于单一类别的缺陷检测重点看混淆矩阵里defect类的召回率也就是实际缺陷里有多少被框出来了。另外一个关键指标是PR曲线下的面积也就是AP值这个值在0.6以上说明模型基本可用如果低于0.4大概率是标注质量有问题或者数据增强不足。混淆矩阵还有一个常见问题矩阵里的行和列总和对不上。这是YOLO在计算时把背景类也算了一行别慌不是数据出错了。4. 毛巾缺陷检测避坑指南标注质量、小目标与类别不平衡4.1 现象XML和TXT标签对不上训练出来和没训练一样有同学拿到数据集后直接开始训练跑了200轮发现mAP一直在0.1以下徘徊甚至训练损失都不怎么降。排查后发现是标签文件的问题——有些人把原始XML直接改后缀变成TXT文件里存的还是XML结构YOLO读标签时按空格切分把一整个XML标签串解析成了一大堆无效数据相当于训练时所有的正样本都失效了。原因就是标签格式转换没做干净。YOLO格式要求每行恰好5个数值一个XML节点转进来会有十几个字段模型完全不知道该怎么学。解决方法是写个标签校验脚本逐行检查每个TXT文件不是5个数值的行全部标记出来然后统一重新转格式。从那以后我每次拿到数据集第一件事就是跑这个校验脚本先确认标签文件的数量和格式再谈训练。import os label_dir dataset/labels for split in [train, val]: txt_files os.listdir(os.path.join(label_dir, split)) for txt in txt_files: path os.path.join(label_dir, split, txt) with open(path, encodingutf-8) as f: lines f.readlines() for idx, line in enumerate(lines): parts line.strip().split() if len(parts) ! 5: print(fbad line: {path}:{idx1})4.2 现象小目标缺陷检测不到漏检严重毛巾缺陷里很多是细小的跳纱、断经在640x640的图上可能就占几十个像素。训练完以后测试大块的破洞和污渍检测得很准但小的缺陷全漏了。这类小目标问题在工业质检里非常典型。原因是缺陷尺寸和anchor尺度不匹配。数据集里目标尺寸分布偏向大目标训练时模型把精力都花在了学习大目标的特征上小目标的梯度贡献太小。另一个原因是imgsz设置偏小缩放到416时小目标直接丢失过半像素。解决方案是先用脚本统计所有标注框的宽高分布看看中位数是多少。然后再决定是调大imgsz还是在训练时开启更高倍数的mosaic增强或者用小anchor的模型变体。YOLOv8里的anchor是自适应学习的小目标多的场景建议把imgsz拉到640以上同时可以调低mosaic概率因为mosaic对小目标的拼接遮挡比较严重。提示毛巾纹理会形成大量背景纹理和跳纱这种细小缺陷在视觉上高度相似。如果精度还是上不去可以试试把模型输入从RGB改成灰度图训练很多织物缺陷用纹理差异比用颜色差异更容易区分。4.3 现象验证集和训练集交叉评估指标虚高还有一种翻车场景是保存数据时顺序没打乱按文件名前80%做训练、后20%做验证。毛巾图片是按采集批次编号的同一批次的毛巾纹理背景高度相似放在验证集里的图片几乎等于训练集图片的轻微变形评估出来的mAP虚高一到真实场景检测就崩。原因是数据划分没有做随机化同批次数据天然具有相关性。工业数据集经常出现这种情况所以划分前必须随机打乱。解决方法是固定随机种子后打乱文件列表再划分分完以后人工抽查验证集的图片确认和训练集没有同源图片。更严格的做法是留出法把同一批次采集的图片全部放同一侧避免数据泄漏。对于这份毛巾数据集建议划完训练集和验证集后检查以下验证集里有没有和训练集连续编号的图片有的话手动移回训练集。4.4 现象训练中BN崩溃损失突然变成NaN训练过程中损失值突然跳成NaN然后整个训练的loss曲线就炸了。这个现象在缺陷检测里并不少见尤其是数据集小、批次值小的时候。BN崩溃的典型特征是训练头几十轮正常突然某几步loss变成NaN后面再也回不去。原因是批次数据里出现了极端值或者在训练中后期学习率没有衰减到位导致梯度爆炸。BN层对小batch的统计值敏感batch4以下时BN统计值震荡严重。处理方式一般是三选一把batch调大让BN统计更稳定或者给输出层加weight decay抑制权值的极端增长再或者换用AdamW优化器并调整初始学习率。在YOLOv8里最简单的做法是把batch提到16同时把优化器的初始学习率调低到0.001大部分BN崩溃问题都能解决。我自己的习惯是训练前先跑几个step做warmup确认损失正常再挂长训练。5. 数据增强与混淆矩阵验证放大435张图的价值5.1 数据增强脚本把435张扩到上千张的边界数据增强对435张这种小数据集的提升非常可观。最有效的增强是mosaic一张训练图由4张图拼接而成相当于变相增大了batch里的目标密度。但mosaic对毛巾这种重复纹理的图片要小心拼接处会形成虚假缺陷边缘模型可能把拼接边界当成缺陷特征我一般把mosaic概率降到0.3同时开启随机亮度、随机旋转和水平翻转。这些参数在YOLOv8的data.yaml里直接配置即可。5.2 混淆矩阵与PR曲线验证模型有没有在瞎猜训练完别急着收工看一眼验证集上的混淆矩阵和PR曲线。对单一类别来说PR曲线的形状比mAP数值更能说明问题曲线往右上角贴得越紧越好如果曲线中段有一个明显下凹说明模型在高置信度区间漏掉了一批无法区分的样本。对毛巾缺陷来说这个下凹往往对应着纹理不清的弱缺陷样本可以回到数据集里把这类图片标注质量再校对一遍。从跑完这批数据之后我每次训练都会强制走一遍这个流程统计标签分布、校验格式、跑短训练确认loss趋势最后才开长训练再也不让标注问题浪费一整个晚上。希望帮到你。本文还有配套的精品资源点击获取
返回列表