皮革缺陷检测数据集处理:从解压校验到YOLOv8训练的完整流程
简介这份皮革缺陷检测数据集面向制造业质检、生皮原料评估与计算机视觉算法研发场景以YOLO格式提供多类别目标检测标注。数据总计490张真实采集图片按训练集429张、验证集41张、测试集20张划分包含CUERO正常皮革、MALO缺陷、REGULAR轻微瑕疵三类标签可直接用于YOLO系列模型训练、验证与迁移学习。压缩包共982个文件整体约15.55MB主体为490张JPEG图像和490个同名TXT标注文件另含1个YAML类别配置文件与1个DOCX说明文档结构清晰、格式规范导入主流框架后即可开展实验。目前已有251人浏览/学习适合工业缺陷检测、畜牧业分级定价、职业教学实训及算法研究等场景。该数据集标注精准、来源真实用户拿到后可依据自带划分快速开始训练也可基于类别结构扩展其他外观检测任务是搭建皮革质检自动化项目的实用数据基础。1. 拿到皮革缺陷检测数据集.zip先分清这是什么再决定怎么用它从网盘或某厂内部服务器下载一个“皮革缺陷检测数据集.zip”只是开始真正花时间的是解压之后的那几步。压缩包是个黑匣子里面是VOC还是COCO标注是矩形框还是贴着缺陷轮廓的多边形样本够不够训练 YOLOv8类别均衡还是严重偏斜这些问题不体检清楚直接套训练脚本大概率翻车。这篇笔记按我处理缺陷检测数据的习惯把从解压、格式体检、转 YOLO 格式、跑通训练到出验证指标的完整路径写一遍。新手能照着复现熟手可重点看第 5 章的权限踩坑记录和第 6 章的验证习惯。2. 解压与数据体检用 sha256 和目录统计判断这份数据值不值得投入拿到 zip 先别急着双击解压。我见过有人解压到一半发现压缩包损坏也有人解压完才发现里面标注格式和预期完全不同白高兴一场。数据体检的意义不只是把文件取出来而是确认三件事压缩包完整、目录结构清晰、标注格式可读。这三件事做扎实后面训练才不返工。2.1 解压前先做三件事校验完整、测试压缩包、识别伪加密先说完整性和压缩包测试。文件越大越值得花这几秒钟。Linux 和 macOS 下我习惯这样ls -lh leather_defect_dataset.zip sha256sum leather_defect_dataset.zip unzip -t leather_defect_dataset.zip第一条看文件大小是否和下载页面一致第二条算哈希值如果你是从源站直接下载的源站通常会贴一个 SHA256对得上才说明文件没被拦腰截断。第三条unzip -t会把压缩包里的每一个文件解压到内存里并做 CRC 校验输出No errors detected才算完整。Windows 用户在 PowerShell 里对应命令是Get-FileHash .\leather_defect_dataset.zip -Algorithm SHA256注意unzip -t是完整测试不是unzip -l只看列表-l只能看到文件名和压缩大小不能发现数据损坏。然后是 zip 伪加密的坑。有些打包工具在创建压缩包时勾了“加密”选项但实际没有设置密码或者工具写入了加密标志位但数据本身没加密。典型现象是解压时弹出“输入密码”对话框但你手上根本没有密码。这不一定是你拿错了包很可能是伪加密。import zipfile z zipfile.ZipFile(leather_defect_dataset.zip) for info in z.infolist(): print(info.filename, info.flag_bits 0x1)zip 文件头里的通用标志位flag_bits最低位是 1 表示该文件项带加密标志。如果这里输出是 1但数据源从未给过密码可以先判断为伪加密。正规处理方式是联系数据提供方确认加密参数或索要正确密码不要尝试绕过如果你自己能重新打包用标准压缩工具重新压缩并去掉加密选项即可。这个检查还有一个价值防止下载到被人改过标志位的可疑文件多一层安全确认。2.2 目录结构与标注格式判断先用 find 和 Python 做一次清点解压之后不要直接打开图片看热闹先把目录结构拉出来find . -type f | sed s|/[^/]*$|| | sort | uniq -c这条命令统计每个目录下的文件数量能一眼看出图片和标注是否分目录存放有没有空目录、重复目录和套娃目录。正常的数据集一般长这样images/train/ 001.jpg 002.jpg ... labels/train/ 001.txt 002.txt ... images/val/ ... labels/val/ ...如果图片和标注混在一个目录里或者出现 train/val/test 三层套娃都要在训练前理清。接着用 Python 统计图片格式、样本数量和各类别分布import os from collections import Counter img_dir images ann_dir labels img_exts (.jpg, .png, .bmp) images [f for f in os.listdir(img_dir) if f.lower().endswith(img_exts)] class_counts Counter() for f in os.listdir(ann_dir): if not f.endswith(.txt): continue with open(os.path.join(ann_dir, f), r) as fp: for line in fp: cls_id line.strip().split()[0] class_counts[cls_id] 1 print(image count:, len(images)) print(class_counts)这段代码假定标注已经是 YOLO 格式的 txt。如果输出里 images 数量和 txt 数量差很多优先怀疑漏标和空标注文件。类别分布 Counter 的输出很直观某个类只有几十个实例而另一个类有几千个后面训练就要做专门处理不能直接硬跑。标注格式怎么认打开一个标注文件看一眼就够了。.xml文件根节点是annotation大概率是 VOC 格式标签文本里能读到 bndbox 坐标。.json文件里出现images和annotations两个顶层数组是 COCO 格式。.json文件里出现shapes和imageWidth是 Labelme 多边形标注。.txt文件每行是纯数字第一个数字是类别 id后面四个是归一化坐标就是 YOLO 格式。这一步对后面的影响很大。皮革缺陷大多是破洞、褶皱、脏污、划痕这类不规则区域标注方经常会用多边形而不是矩形框。如果拿到的是 Labelme 多边形标注不能直接训练检测模型需要先转成 YOLO 能吃的格式——这就是下一章要做的事。提示不做体检直接训练最常见的代价是训练到一半发现图片和标注编号对不上或者类别 id 和 names 顺序错位。错一个 id整个模型学到的类别就是乱的等于白跑。3. 把 Labelme 多边形标注转成 YOLO 格式转换脚本与四个容易错的地方皮革缺陷检测很少用正矩形框标数据因为缺陷边缘不规则标注员习惯用多边形贴着缺陷轮廓画。Labelme 保存出来的 json 里每个 shape 的 label 是类别名points 是多边形顶点列表。YOLO 检测格式需要的是归一化后的中心点坐标和宽高。转换脚本逻辑不复杂但细节很容易错。3.1 从 Labelme json 里提取边界框并归一化核心代码就十几行import json import os def labelme_to_yolo_txt(json_path, out_path, class_names): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] pts shape[points] xs [p[0] for p in pts] ys [p[1] for p in pts] xmin, xmax min(xs), max(xs) ymin, ymax min(ys), max(ys) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h box_w (xmax - xmin) / img_w box_h (ymax - ymin) / img_h cls_id class_names.index(label) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines))逻辑上先取多边形的横纵坐标极值得到外接矩形再统一除以图片宽高做归一化。class_names是一个列表比如[hole, stain, wrinkle, scratch]index()方法把类别名映射成从 0 开始的整数 id。这句是很多新手翻车的地方——类别名有大小写差异、中英文混杂或者训练 YAML 里 names 顺序和这里不一致都会导致模型标签错乱。转换后随便打开一个 txt 看一眼第一列应该是一个很小的整数后面四列是 0 到 1 之间的小数。这里有一个设计选择要说明我转换用的是外接矩形框而不是多边形分割。皮革缺陷检测如果用的是yolo detect任务只需要边界框如果你后面想跑yolo segment那就要把 points 量化成归一化的多边形坐标写入分割格式代码和这完全不同。缺陷形状极度不规则、矩形框会引入大量背景噪声时才值得考虑 segmentation 路线。3.2 按类别分层划分 train/val 并固定随机种子划分数据集时最忌简单随机打乱。皮革缺陷数据集普遍存在类别不均衡——脏污样本可能有几千个破洞只有几十个。纯随机划分可能把少量破洞样本全部划进训练集验证集里一个都没有得到的 mAP 就是虚高的。所以划分前先按标签做分层抽样import os import random from collections import defaultdict random.seed(42) img_dir images_raw ann_dir labels_raw val_ratio 0.2 images [f for f in os.listdir(img_dir) if f.endswith(.jpg)] samples [] for img in images: txt_name img.replace(.jpg, .txt) txt_path os.path.join(ann_dir, txt_name) if not os.path.exists(txt_path): continue with open(txt_path) as fp: cls_ids set(line.split()[0] for line in fp) samples.append((img, cls_ids)) grouped defaultdict(list) for img, cls_ids in samples: for cid in cls_ids: grouped[cid].append(img) val_imgs set() for cid, imgs in grouped.items(): random.shuffle(imgs) n_val max(1, int(len(imgs) * val_ratio)) val_imgs.update(imgs[:n_val]) train_imgs [s[0] for s in samples if s[0] not in val_imgs] print(train:, len(train_imgs), val:, len(val_imgs))这段代码先统计每张图片包含哪些类别再按类别分组保证每个类别在验证集中都有至少一个样本。random.seed(42)固定随机种子多次运行结果一致这是可复现实验的基本习惯。实际操作中我还会把划分结果保存成train.txt和val.txt两个文件后续训练脚本直接读文件列表比每次重新划分稳定。3.3 转格式的四个易错点分母写错。归一化必须除以原始图片的真实宽高不是除以多边形坐标的最大值也不是除以网络输入尺寸。用后者得到的结果在训练时会二次拉伸边界框位置全偏。空标注文件。一张没有任何缺陷的正常皮料图片如果 Labelme 里没有 shapes转换脚本输出一个空 txt。YOLO 训练遇到空 txt 一般会直接报错或者跳过该样本。建议转换后统一清理空 txt 要么删掉图片要么把这张图放到训练集的负样本池里但要做好背景和负样本的标注约定不能放任不管。类别名不一致。同一个标注员手误把“Wrinkle”和“wrinkle”当成了两个类转出来是 4 类训练 YAML 里只有 3 类id 全乱。转换前先收集所有 json 里出现过的 label 做一次去重和纠错再生成 class_names。图片和标注名不匹配。常见的是 png 图片配了 jpg 标注名或者文件名里带空格和中文。转格式时统一改成小写字母、下划线命名规避后续在 Windows 和 Linux 之间复制文件踩到文件名编码问题。4. 用 YOLOv8 训练皮革缺陷检测本地数据 YAML 与三处关键参数格式转好、数据划分好训练这一步反而是最简单的。真正影响皮革缺陷检测效果的不是epochs和batch而是数据 YAML 的类别顺序、输入分辨率、以及针对小样本设计的增强策略。我一般先用yolov8n跑通流程确认数据没问题后再上yolov8m或yolov8s避免一上来就用大模型浪费时间。4.1 data.yaml类别 id 必须和转换脚本里的 class_names 一致把下面的 YAML 放到数据集根目录path: /data/leather train: images/train val: images/val names: 0: hole 1: stain 2: wrinkle 3: scratchpath是数据集根目录的绝对路径train和val都是相对path的目录。这里最容易出的问题不是语法而是 names 的顺序。训练脚本读取names[0]对应标注文件里第一个数字如果你的转换脚本里class_names是[scratch, wrinkle, stain, hole]那 YAML 里必须原样写不能按常识调成“看起来更整齐”的顺序。检测模型并不关心类别在语义上该怎么排序它只认下标。4.2 训练命令imgsz 是第一个要调大的参数yolo detect train \ dataleather.yaml \ modelyolov8n.pt \ pretrainedTrue \ epochs200 \ batch16 \ imgsz1280 \ hsv_h0.0 \ hsv_s0.2 \ hsv_v0.2 \ mosaic0.5 \ patience50 \ cacheram \ projectleather_run \ nameexp01逐个说清楚我为什么这么设。pretrainedTrue是加载 COCO 预训练权重对数据量不足千张的皮革数据集帮助巨大不要关。epochs200和patience50是配套用的模型在验证集上连续 50 个 epoch 没有提升就早停省时间也防止过拟合。imgsz1280是最关键的一项。皮革缺陷里的破洞和细划痕通常只有几十像素640 输入下这些目标在下采样阶段直接丢了。1280 能明显改善小目标召回率代价是显存占用量涨到 640 的 4 倍左右。如果显卡放不下优先降 batch 而不是降 imgsz8 和 16 的 batch 对最终精度的差异远小于分辨率的影响。显存实在不够可以用 640 训练加yolo predict时开 TTA。batch16是 8GB 级别显卡在 1280 输入下比较稳的选择实测显存不够就减到 8。cacheram把图片缓存到内存避免训练时频繁读磁盘皮革数据集图片通常不大几百 MB 内存就能换明显的训练速度提升。4.3 数据增强皮革表面是低纹理域别照搬自然图像的增强参数YOLOv8 默认的增强参数是按自然图像调的直接用皮革数据上容易过猛。这里的核心参数是mosaic、hsv_h、hsv_s、hsv_v。mosaic0.5表示一半训练样本由 4 张图拼接而成对小样本数据是有效的泛化手段。但如果你的数据集总量不到几百张mosaic 概率我建议再降到 0.3否则拼接出来的图像里缺陷周围全是来自不同图片的纹理拼接缝模型容易学会“接缝就是缺陷”的错误关联。hsv_h0.0表示色调不做调整。皮革本身是低饱和度材质色调翻太多等于让模型去适应不存在的颜色变化。hsv_s0.2、hsv_v0.2只做轻微饱和度与亮度扰动模拟不同流水线上照明导致的色差但不过度。类别不均衡在数据层面解决不要在参数里硬凑。我常用的做法是对破洞这类少量样本做离线增强比如小角度旋转、镜像、在皮料背景上换位置贴图把副本补进训练目录。目标是把最少类别也补齐到几百个实例不然模型无论如何都学不好这个类。提示训练日志里留意每个 epoch 的 box_loss 和 cls_loss。如果 cls_loss 降得很慢而 box_loss 正常大概率是类别映射错位或者某个类别样本太少先别急着调学习率。5. 皮革缺陷检测常见问题排查loss 降、mAP 不动与换皮料掉点怎么定位这个章节值得重点看。训练能跑通是常态跑出来的模型能用才是目标。我把自己在皮革缺陷检测上踩过的几类问题按“现象 → 原因 → 解决”的格式写出来这些问题在 YOLO 系检测模型里都算典型。5.1 现象训练 loss 一直在降mAP50 卡在 0.35 附近再也不动原因分析这是典型的正负样本失衡症状。皮革表面绝大多数区域是“无缺陷”背景模型把有限的学习容量大部分用在了识别背景上真正能区分缺陷的特征没有被强化。另一个常见原因是多数类比如脏污贡献了 loss 的主要部分少数类破洞虽然 loss 在降但绝对值太小权重更新方向被多数类带偏。解决思路先看第 2 章统计出的类别分布表如果最少类别实例数除以最多类别小于 1:10优先补少数类样本。快速做法是把少数类图片复制一份并施加不同的水平翻转和旋转重新生成标注后加入训练目录长期做法是继续标注或引入外部数据。确认类别分布没大问题后再把imgsz从 640 换到 1280因为小目标特征在高分辨率下才更明显。5.2 现象褶皱和脏污在验证集上互相误判召回率虚高或崩塌原因分析这类混淆往往不是模型 bug而是标注和问题定义本身有歧义。皮革褶皱在阴暗光照下形态接近长条脏污加上不同标注员对边缘区域的判断不一致同一个明显的褶皱有人标 wrinkle有人标 stain。模型学到的是标注者的习惯而不是缺陷的本质。解决思路先做一次标注复核把两个类别的误检图各挑 50 张打印出来和标注方一起定一个区分标准比如“以是否有明显深度起伏为褶皱以是否有颜色沉积为脏污”然后修正标注重新训练。如果你的业务不关心具体缺陷类型只关心“有没有表面异常”把这两类合并成一个surface_anomaly类模型的 mAP 通常会立刻提升且工程上更可靠。5.3 现象训练集和验证集同源时 mAP 漂亮换一批新皮料直接掉点原因分析这是领域漂移。训练数据可能来自某一家皮革厂的某一批次皮料表面颜色、纹路、光照高度一致实际部署时换了一家供应商皮料基底从浅棕色变成黑色或者表面褶皱密度完全不同模型立刻失灵。解决思路在训练阶段就拉开数据多样性把hsv_s和hsv_v从 0.1 提回 0.3让模型见过更多颜色和亮度范围。更彻底的做法是在数据集中刻意混入不同批次的皮料图像确保每类缺陷都有至少 50 个实例来自不同皮料基底。部署前做一次小批次验证拿 30 张新皮料图片直接跑预测如果 mAP 掉幅超过 15%不要迷信原模型要回到数据收集环节。5.4 现象zip 解压时提示输入密码或中文文件名乱码这两个数据包处理问题也算典型。伪加密在前文已经提过现象是 unzip 要求输入密码但数据方没给密码。先跑 zipfile 看 flag_bits确认是伪加密后联系数据提供方处理而不是硬猜密码。中文乱码多出现在 Windows 打包、Linux 解压的场景压缩包内文件名是 GBK 编码Linux 默认按 UTF-8 解释解压后显示一堆乱码。解决方法是unzip -O gbk leather_defect_dataset.zip但 macOS 系统和某些发行版的 unzip 不认-O参数。这种情况我把文件拷到 Windows 上用 7-Zip 解压或者在 Windows 的 PowerShell 里用Expand-Archive中文名不会乱。这个坑不影响模型但影响团队协作——文件名乱码的图片一旦进入训练目录后续排查问题会浪费大量时间。6. 验证模型真实水平混淆矩阵、预测图与置信度阈值的选择习惯训练结束后的验证工作经常被简化成一句“mAP 多少”但 mAP 只反映平均值不反映模型的失败模式。我现在验证皮革缺陷检测模型只看两个东西混淆矩阵和预测图。6.1 用 val 接口输出混淆矩阵from ultralytics import YOLO model YOLO(leather_run/exp01/weights/best.pt) metrics model.val(dataleather.yaml, splitval, conf0.35, iou0.5) print(metrics.box.confusion_matrix.matrix)这个混淆矩阵的行是真实类别列是预测类别。对角线数值越大越好非对角线上的数值代表误检方向。比如第 2 行第 3 列的值偏高说明 wrinkle 经常被预测成 stain这时候针对两类的区分策略比盲目调conf更有用。矩阵右下角通常是背景类这一行数值高说明背景误检严重需要提高conf阈值或者在数据中增加困难负样本。6.2 批量预测并输出预测图和裁剪图yolo predict \ modelleather_run/exp01/weights/best.pt \ sourcehard_samples/ \ saveTrue \ save_txtTrue \ save_cropTrue \ conf0.35 \ iou0.5saveTrue保存带预测框的原图save_cropTrue额外把每个预测框的缺陷区域单独裁出来。我会把 hard_samples 里换批次的皮料图跑一遍打开预测图看两点预测框是否紧贴缺陷边缘漏检的缺陷是不是集中在某一种纹理背景下。如果裁剪图里大量出现把正常皮料纹路当成缺陷的情况说明模型的感受野学到了纹理特征而不是缺陷特征这就回到数据层面去解决。阈值怎么设我的习惯是先按conf0.25跑一批看漏检再按conf0.5跑一批看误检取两者交叉区间的拐点。皮革质检场景里漏检缺陷的代价客户投诉赔偿远高于误检的代价人工复检所以部署时我倾向偏低阈值宁可多拦截也不能放过。这个数字每个数据分布都不一样但流程是通用的。最近再处理缺陷检测数据集我几乎雷打不动先做压缩包校验、格式体检、分层划分这三步再跑一次最小训练打印基线。之前跳过体检直接训练白跑过一整天只因坐标归一化分母写错。这套流程现在帮我省掉了很多返工时间希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →