ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

行李箱缺陷检测数据集:VOC/YOLO双格式与YOLOv8训练全解析

行李箱缺陷检测数据集:VOC/YOLO双格式与YOLOv8训练全解析 简介一套行李箱缺陷检测目标检测数据集包含650张清晰jpg图像及对应VOC格式xml与YOLO格式txt标注覆盖“damaged”与“good_condition”两个类别矩形框标注共计936个可直接用于缺陷检测、质量检验等场景的模型训练与算法验证。压缩包内共1952个文件其中650张图片、650个xml标注、652个txt标注及相关配置文件整体大小25.11MB目录按JPEGImages、Annotations、labels划分便于快速接入主流训练框架。已有126人学习下载数据均经人工复核标注格式规范可省去大量数据清洗与格式转换时间。适合目标检测初学者练习YOLO/VOC训练流程也可供工业质检、物流分拣等领域的开发者作为算法验证基准。1. 行李箱缺陷检测数据集650 张双格式标注能不能直接拿来训 YOLO做工业质检或者物流分拣相关的视觉项目时找数据集是最头疼的事。公开数据集里行李箱这个品类很少见尤其是带“damaged”和“good_condition”这种成对标签的基本只能自己拿 labelimg 一张张框。这份行李箱缺陷检测数据集一共 650 张图片同时给了 VOC 的 xml 和 YOLO 的 txt 两种标注格式标签就两类damaged损坏和 good_condition完好算下来总共 936 个标注框。对想快速验证 YOLO 检测流程、或者做行李箱外观质检 demo 的从业者来说这套数据能省掉大半天的标注时间。唯一要提前有心理预期的是damaged 只有 199 框类别不平衡是明摆着的后面训练和评估得围绕这个事实来调整。2. 数据集内部结构三个文件夹、650 份文件标注格式先对齐再谈训练2.1 JPEGImages、Annotations、labels 三件套与文件命名规则压缩包解开之后是标准的检测数据集目录布局三个文件夹各司其职。JPEGImages 里是 650 张 jpg 原图Annotations 里是 650 个 xml 标注文件labels 里是 650 个 txt 文件。三个文件夹的文件名是一一对应的比如 xyxr_image626.jpg 对应的是 Annotations 下的 xyxr_image626.xml 和 labels 下的 xyxr_image626.txt。这种命名对应关系是 VOC 时代遗留下来的规范YOLO 训练时读取数据也依赖这个强对应。文件名前缀是 xyxr_image后面跟三位数字编号从 626 到 580 这一批样本看起来是同一采集批次出来的拍摄条件应该比较统一。图片清晰度标注为“清晰”分辨率满足常规目标检测需求不需要额外做超分或去噪预处理。实际使用前建议自己写一行命令核对三边文件数量是否完全一致。常见做法是ls JPEGImages | wc -l ls Annotations | wc -l ls labels | wc -l # 检查是否有缺失对应文件的情况 for f in JPEGImages/*.jpg; do base$(basename $f .jpg) [ -f Annotations/$base.xml ] || echo missing xml: $base [ -f labels/$base.txt ] || echo missing txt: $base done三个wc -l的输出应该都是 650循环检查如果没有任何输出说明三边对应关系完整。这一步看似多余但实际从网上下载的数据集里偶尔会碰到 xml 和 txt 文件数量对不上的情况尤其是经过多次压缩解压、转存之后。先把对应关系验证一遍后面跑训练脚本的时候才不会因为某个文件名配对不上而中断。参数层面需要注意一点YOLO 系列读取数据时是按图片文件列表去匹配同名的 txt 或 xml不是反过来。所以只要 JPEGImages 里的图是完整的剩下的就是保证同名文件都在。2.2 标签分布统计damaged 199 框、good_condition 737 框意味着什么从摘要给出的统计数字看两个类别的框数差异不小。damaged 类别 199 框good_condition 类别 737 框总框数 936平均每张图 1.44 个框。标签名称是[damaged, good_condition]其中 good_condition 是行李箱外观完好的状态框damaged 是存在磕碰、划痕、破损等缺陷的状态框。这个分布比例大约是 1:3.7damaged 样本偏少。放到目标检测任务里模型会更倾向于把候选框预测成 good_condition因为这样在训练集上损失更小。实际推理时可能出现漏检——把有缺陷的箱子判成完好的这在质检场景里是比误报更严重的错误。处理思路通常有两个方向。一个是训练时给 damaged 类别更高的 loss 权重比如在 YOLOv8 的 class loss 里按类别频率倒数设置权重另一个是评估时不只看整体 mAP单独看 damaged 类别的 recall确保缺陷框没有被吞掉。数据增强里的随机裁剪、复制粘贴也需要优先照顾 damaged 框不要让增强过程把小目标缺陷放得更小。另外注意一个细节标签名称没有加空格和特殊字符这很好。VOC 格式里类别名直接写在name节点里YOLO 格式里类别名映射成数字时靠一个 classes 列表来定顺序如果类别名里有空格写解析脚本时容易踩坑。这个数据集的类别名干净省了一档事。3. VOC 与 YOLO 双格式标签解读xml 和 txt 怎么对齐坐标换算看清归一化3.1 VOC xml 标注文件的核心字段拆解VOC 格式的标注文件本质是一个 XML 文档记录了图片路径、尺寸、目标类别和边界框坐标。随便打开一个标注文件结构基本如下annotation folderJPEGImages/folder filenamexyxr_image626.jpg/filename size width1280/width height720/height depth3/depth /size object namedamaged/name bndbox xmin420/xmin ymin260/ymin xmax580/xmax ymax370/ymax /bndbox /object /annotationsize节点里的 width 和 height 是原图的宽高像素值这对后面 YOLO 归一化换算至关重要。object节点每个目标一个包含类别名name和边界框bndboxxmin、ymin 是左上角坐标xmax、ymax 是右下角坐标单位都是像素。注意 xmin、ymin 的坐标原点在图片左上角x 轴向右增大y 轴向下增大。这个约定和 OpenCV、PIL 的像素坐标系一致但如果某些标注工具用的是中心点加宽高存储或者坐标系原点在左下角转换时就要额外处理。这个数据集的 VOC 标注是标准的左上角原点方式直接解析即可。标注工具的差异也可能造成边界框是闭区间还是开区间的细微区别。一般情况下 xmax、ymax 指的是框右下角像素的坐标但有的工具会用 xmax xmin width 的语义多一个像素少一个像素对检测结果几乎没影响不用纠结到像素级。3.2 txt 标签格式与归一化坐标换算方法labels 文件夹里的 txt 文件是 YOLO 格式的标注每一行对应一个目标格式是五个空格分隔的数字0 0.390625 0.437500 0.125000 0.152778 1 0.721094 0.581944 0.176562 0.263889第一列是类别索引0 对应 damaged1 对应 good_condition这个顺序来自数据集定义时 classes 列表的顺序。后面四个数字依次是归一化后的中心点 x、中心点 y、归一化宽度 w、归一化高度 h。注意是中心点加宽高的表示方式不是左上角加右下角。换算公式很简单center_x (xmin xmax) / 2.0 / width center_y (ymin ymax) / 2.0 / height w (xmax - xmin) / width h (ymax - ymin) / height如果图片宽度是 1280xmin 是 420、xmax 是 580那归一化宽度是 (580-420)/1280 0.125中心点 x 是 (420580)/2/1280 0.390625和上面示例完全吻合。从 VOC 转 YOLO 格式时最关键的坑就是归一化分母必须用size里的原始宽高。有些标注工具导出的 xml 里 width/height 和实际图片尺寸不一致常见原因是标注时图片被缩放预览过但保存的尺寸信息没更新。如果转换出来的坐标明显偏大或者越界先检查 xml 里的 size 是否和真实图片尺寸一致通常用 Python 的 PIL 库读一下图片原始尺寸就能验证from PIL import Image img Image.open(JPEGImages/xyxr_image626.jpg) print(img.size) # (1280, 720)我一般写完转换脚本后会随机挑三张图把解析出来的框画在原图上做可视化校验。框的位置和轮廓跟图片内容对得上才认为这批 txt 格式是可靠的。画框用 OpenCV 几行搞定这一步值得做因为后面训练跑半天发现坐标全错再回头排查时间成本高得多。3.3 自写转换脚本的常见做法与参数选择如果想把 VOC 转成 YOLO 格式或者反过来把 YOLO 转回 VOC 做可视化写个一次性脚本最省事。下面是 VOC 转 YOLO 的参考脚本import os import xml.etree.ElementTree as ET class_name_to_id {damaged: 0, good_condition: 1} def voc_to_yolo(xml_file, out_txt_file): tree ET.parse(xml_file) root tree.getroot() size root.find(size) width int(size.find(width).text) height int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text.strip() if name not in class_name_to_id: continue class_id class_name_to_id[name] 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) cx (xmin xmax) / 2.0 / width cy (ymin ymax) / 2.0 / height w (xmax - xmin) / width h (ymax - ymin) / height lines.append(f{class_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_txt_file, w) as f: f.write(\n.join(lines)) annotations_dir Annotations labels_dir labels os.makedirs(labels_dir, exist_okTrue) for xml_name in os.listdir(annotations_dir): if not xml_name.endswith(.xml): continue base os.path.splitext(xml_name)[0] xml_path os.path.join(annotations_dir, xml_name) txt_path os.path.join(labels_dir, base .txt) voc_to_yolo(xml_path, txt_path)脚本核心逻辑就是把 xml 里的像素坐标读出来按前文公式换算后写到 txt。class_name_to_id字典的键值顺序必须和训练时 classes 列表一致一旦搞反模型会把 damaged 当 good_condition 来学推理结果全错。宽高用了.text转 float 再参与除法避免整数除法截断。输出坐标保留六位小数对检测任务来说精度完全足够。这个脚本适合在拿到新数据集时做格式统一比如手里有几批不同来源的数据有的给 VOC、有的给 YOLO统一成 YOLO 格式后丢进同一个训练流程。反向转换 YOLO 转 VOC 也同理把归一化坐标乘回宽高即可注意类别 id 到类名的映射反过来。4. 用 YOLOv8 训练行李箱缺陷检测数据划分、配置文件与训练命令4.1 数据集划分策略与脚本拿到标注数据后第一件事不是急着训练而是把数据划分成训练集、验证集和测试集。650 张图不算多常见的划分比例是 8:1:1也就是 520 张训练、65 张验证、65 张测试。如果对精度要求高也可以按 9:1 只分训练和验证测试直接用验证集代替但那样评估分数会偏乐观。划分时要保证的是随机性同时最好记录下每个集合的文件清单方便复现。下面是简单的划分脚本import os import random from sklearn.model_selection import train_test_split image_dir JPEGImages train_txt train.txt val_txt val.txt test_txt test.txt images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] images.sort() # 保证划分结果可复现 random.seed(42) train_val, test train_test_split(images, test_size0.1, random_state42) train, val train_test_split(train_val, test_size0.1 / 0.9, random_state42) def write_list(path, img_list): with open(path, w) as f: for img in img_list: base os.path.splitext(img)[0] f.write(fdata/images/{img}\n) os.makedirs(data/images, exist_okTrue) os.makedirs(data/labels, exist_okTrue) write_list(train_txt, train) write_list(val_txt, val) write_list(test_txt, test) print(len(train), len(val), len(test))这里用了random.seed(42)固定随机种子保证每次运行划分结果一致调试时可复现。train_test_split的test_size参数注意第二次划分时要把比例换算成相对于剩余数据的比例先分出 10% 测试剩下 90%再从中分出 10% 验证实际验证占比是 9% 左右所以test_size0.1/0.9算出来的结果接近 9:1 里的 1 份。写出的 train.txt、val.txt 里存的是图片的绝对路径或相对路径YOLO 训练时通过这个文件列表去定位图片对应标签。实际数据存放结构不一定非要把图片复制到 data 目录直接用原始路径也可以只要训练配置里的路径指向正确。4.2 data.yaml 配置与关键参数解释YOLOv8 用 yaml 文件描述数据集的路径、类别信息和类别数量。对于这套行李箱数据配置文件如下path: /path/to/luggage_dataset train: train.txt val: val.txt test: test.txt names: 0: damaged 1: good_conditionpath字段指定数据集根目录train和val可以是 txt 文件路径也可以是图片目录路径。如果用 txt 文件里面每一行是图片的绝对路径或相对于path的路径。names字典的索引必须和 txt 标注里的第一列类别 id 严格对应damaged 是 0、good_condition 是 1写反了模型训练时 loss 直接乱掉。nc在 YOLOv8 里可以从 names 列表长度自动推断不显式写也可以但建议显式写上nc: 2少一层隐式依赖。如果是 YOLOv5则必须要写nc: 2v8 可以省略但有比没有好。4.3 训练命令与超参数设置训练用 YOLOv8 的命令行入口最简形式如下yolo train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0模型选 yolov8n 还是 yolov8s取决于硬件和精度需求。650 张图的小数据集上yolov8n 是合理起点参数量小、不容易过拟合即使一张消费级显卡也能轻松跑完 100 轮。如果显存充裕并且想追求更高精度换 yolov8s 微调也能更快收敛但 damaged 类别样本少模型参数越多过拟合风险越大。imgsz640是默认推理尺寸。这套数据集的图片分辨率标注为清晰但没给出具体像素值。要是原图接近 1920x1080那 640 的输入尺寸等于把图缩小到三分之一小目标缺陷可能被压没。一种办法是先用yolo detect predict跑几张看看如果 damaged 框都比较小可以试试imgsz960或者 1280代价是显存占用和训练时间上升。目标检测里输入尺寸是个先验参数要跟目标尺度匹配不是越大越好。batch16在 650 张图的规模下是一轮约 40 个 step100 轮就是 4000 步对收敛来说足够。batch 大小主要受显存约束显存不够就调小到 8 或 4同时可以考虑梯度累积来保持有效 batch 不变。epochs100算是保守设置。小数据集上训练轮数太多容易过拟合太少欠拟合。可以在训练结束后对比最佳权重在验证集上的 mAP如果训练 loss 还在明显下降但验证 loss 已经回升说明过拟合出现了epochs 要往回减或者加正则化。4.4 训练结果评估看哪些指标才不会被 mAP 骗训练完成后Ultralytics 会在 runs/detect/train 目录下生成 weights/best.pt、weights/last.pt 以及一堆结果图表。最直观的指标是验证集上的 mAP50 和 mAP50-95。但在这个类别不平衡的数据集上只看总体 mAP 容易被 good_condition 的高精度带偏。需要单独看 per-class 的 AP 值。YOLOv8 的结果文件里results.csv 包含每个类别的 AP50 和 AP50-95。重点关注 damaged 那一列的数值。正常情况下 damaged 的 AP 会明显低于 good_condition因为样本量少。如果 damaged 的 AP50 低于 0.5说明模型基本没学会找缺陷需要从数据增强、类别权重、损失函数这几个方向去调。如果 good_condition 很高的同时 damaged 很低那就是不平衡导致的偏置不是模型结构的问题。混淆矩阵也是一个值得看的东西。val 阶段输出的 confusion_matrix.png 能直接看到有多少 damaged 被预测成了 good_condition这个比例如果偏高后面部署到质检线上就是漏检的隐患。5. 避坑清单训练行李箱缺陷检测时最容易翻车的五个问题5.1 文件名对应关系错位图片和标签张冠李戴现象训练过程 loss 正常下降但验证集 mAP 始终上不去随机抽几张预测图发现框的位置明显不对。原因数据集在传输或转存过程中图片文件和标签文件没有按同名对应关系重新配对。比如 JPEGImages 里某张图和 labels 里同名 txt 不是同一张图的内容模型学到的是错误的监督信号。另一种常见情况是 windows 和 linux 系统间文件排序规则不同批量改名时把序号搞错位了。解决训练前强制跑一遍三重文件名比对。用sorted(os.listdir(JPEGImages))和sorted(os.listdir(labels))取扩展名前的内容做集合差确保两边完全一致。再随机挑几张图把标注框画上去人工核对确认类别和位置没有明显异常。这个检查只需要几分钟但能避免几小时的无效训练。5.2 damaged 和 good_condition 框数比例悬殊导致漏检现象训练完成后测试集上 good_condition 检测得很好damaged 频繁漏检尤其是小面积的划痕和磕碰缺陷。原因这是典型的类别不平衡问题。737 个 good_condition 框对 199 个 damaged 框模型在训练时天然倾斜到多数的 good_condition 上。加上缺陷区域往往面积小、纹理复杂在 640 输入尺寸下经过多次下采样特征图上的响应很弱。解决第一步是把输入尺寸适当加大到 960 甚至 1280保证小缺陷在特征图上还有足够的像素。第二步在 loss 上做文章——YOLOv8 的 loss 里可以用cls和box的权重配比来调节但更直接的做法是在数据加载层面做复制粘贴增强把 damaged 框连同小区域贴到其他图片的行李箱或者背景上等价于增加了 damaged 样本量。第三步是调置信度阈值推理时把 conf 从默认的 0.25 降到 0.1牺牲一点 precision 换 recall适合质检场景宁可多报不可漏检的需求。5.3 标注边界语义不一致good_condition 框内的细微损坏现象验证集 mAP 不低但实际部署时发现有些明显有划痕的箱子被识别成 good_condition。原因问题出在标注的边界标准上。数据集的标注是人工打的不同标注者对“damaged”和“good_condition”的判定尺度可能不同。有的标注者把轻微运输磨痕也算 damaged有的只把明显破损算进去。这就造成类别边界模糊模型学到的决策边界是标注者标准的平均值而不是理想中的“是否有缺陷”。解决拿到数据后先通读一遍 damaged 类别的所有框感受标注者的打标尺度。如果发现边界案例较多建议自己在训练前做一次标签清洗把明显标错的框修正一下。具体做法是写个小脚本遍历所有 xml凡是有 damaged 类别的图片全部抽出来用 OpenCV 画框后按文件名排序一张张过目修正之后再转 YOLO 格式。这步会花一两个小时但这是数据质量投资回报直接体现在测试集 damaged 类别的 AP 和 recall 上。还有一个更隐蔽的现象同一样品在运输过程中可能多处受损但标注时只框了最明显的损伤区域。这样模型训练时会把这个框内不算严重的区域当作正样本对“严重”语义的区分度就更低了。这个属于标注质量的固有局限规避方式是评估时只看 recall不苛求定位精度。5.4 归一化坐标越界txt 里出现大于 1 或小于 0 的值现象训练时出现 RuntimeError 或者警告提示某些 box 坐标超出 [0, 1] 范围。原因VOC 转 YOLO 时如果 xml 里的 xmax 或 ymax 超过了图片实际尺寸比如标注时鼠标拖过了图片边界归一化后就会得到大于 1 的数。这类越界框如果不处理训练时会导致 anchor 匹配逻辑异常甚至梯度爆炸。解决写一个校验脚本扫描所有 txt 文件的每一行检查五个数值是否都在合法范围。发现越界就把对应的目标直接裁回边界内或者删除该目标框。裁剪比直接删更多地保留了信息但要注意裁剪后的框面积不能过小否则没有训练价值。示例def clamp_txt_line(line, eps1e-6): parts line.strip().split() cls_id parts[0] cx, cy, w, h map(float, parts[1:]) cx max(0.0, min(1.0, cx)) cy max(0.0, min(1.0, cy)) w max(eps, min(1.0, w)) h max(eps, min(1.0, h)) return f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}参数说明eps1e-6是防止宽度或高度被裁剪成 0 导致后续 loss 计算除零。裁剪的中心点如果原本接近边界裁剪后框的几何中心会偏移但这个偏差对检测精度的影响可以忽略。最稳妥的做法还是回到 xml 源文件去定位是哪张图的哪个框出了问题从源头修正。5.5 训练集和验证集划分不当导致评估结果虚高现象训练 loss 收敛得很好验证集 mAP50 能到 0.9 以上但换了一批真实场景图片测试效果立刻垮掉。原因划分时没有做类别分层或者同一批拍摄条件下的图片同时出现在训练和验证集里。像 xyxr_image626.jpg 和 xyxr_image627.jpg 这种连续编号的图片很可能来自同一个行李箱的不同角度光照、背景高度相似。如果训练集和验证集都包含了同批次图片模型实际上是在熟悉背景和光照而不是在学习箱体缺陷。解决划分时按拍摄批次或场景分组保证同一个来源的图片不会同时落在训练和验证集。最简单的方式是按文件名的编号前缀或连续区间做分组划分而不是纯随机。如果无法确定分组信息可以手动图片聚类后划分。另外验证集里的 damaged 框数量要尽量跟训练集占比一致避免验证集全是 good_condition 的箱子导致评估结果乐观。按train_test_split的stratify参数按类别分布分层抽样也可行但要确保分层维度是图片级而不是框级。6. 进阶玩法用数据增强和置信度调优把 damaged 类别榨干数据增强是弥补 damaged 样本不足最有效的手段。650 张图、199 个 damaged 框这个体量下不做增强基本只能拿个 baseline。Ultralytics YOLOv8 内置了丰富的在线增强策略训练参数里直接可调不需要额外写增强代码。常用增强参数分两组。几何变换组包括hsv_h、hsv_s、hsv_v控制颜色抖动degrees控制旋转角度translate控制平移比例scale控制缩放范围fliplr控制水平翻转概率。对于行李箱这个品类水平翻转是安全的因为行李箱左右对称类别语义不会因为翻转而改变。旋转角度不要给太大工业质检场景中行李箱基本都是水平摆放旋转 30 度以上的增强样本反而会偏离真实分布。scale0.5意味着训练时图片会在 0.5 到 1.5 倍之间随机缩放这有助于模型应对不同距离下的成像尺寸变化。比较关键的是 mosaic 增强把四张图拼成一张训练默认是开启的。mosaic 对提升小目标检测能力有明显帮助因为它把多张图的上下文混合在一起模型被迫在更复杂的背景中定位目标。代价是在数据集的类别边界本身不清晰时mosaic 会把不同风格的样本硬拼在一起干扰模型的类别决策。我的习惯是训练早期开启 mosaic 帮助收敛最后 20 个 epoch 关闭只做基本几何增强让模型在真实尺寸分布上微调。推理侧的调优对部署阶段最实用。YOLOv8 推理时默认置信度阈值 0.25NMS IoU 阈值 0.7。在行李箱缺陷检测场景下这两个参数对漏检率影响很大。用验证集做一次阈值扫描画出 precision-recall 曲线找到 damaged 类别 recall 超过 0.9 时对应的阈值点。实际操作中更高效的方法是用 Ultralytics 提供的 val 模式输出每张图每个框的置信度然后在后处理脚本里重新按阈值过滤给定一个候选阈值列表统计不同阈值下各类别的 precision、recall 和 F1 值选 F1 最高的那组参数作为部署配置。常见结论是质检项目里置信度阈值压到 0.1-0.15NMS IoU 保持 0.5 左右漏检率最可控。还有一个容易被忽略的验证技巧把训练时没有见过的 65 张测试图片单独跑一遍推理把conf0.1的预测结果全部画出来逐张人工检查哪些是真正的漏检、哪些是误检。这步看起来原始但比任何指标的感知都直接。我看到过不少项目 mAP50 报得挺高一落地到产线就被现场漏检打脸就是因为指标和真实场景脱节。从那以后我每次拿新数据集训练完都强制自己走一遍这个流程——画出全部测试图预测结果、逐张翻看、按误检漏检分类记录再决定是调阈值还是补数据。上次做行李箱缺陷检测时就是靠这一步发现了标注尺度不一致的问题回头洗了一轮数据damaged 的 recall 从 0.76 拉到了 0.88希望这个习惯也对你有用。这套数据集双格式齐全、标注干净按上面的流程走一遍能快速跑通行李箱缺陷检测的完整链路。直接拿压缩包里的图片和标注开工就行省下自己找图和打标签的时间把精力花在调优和踩坑上。本文还有配套的精品资源点击获取
返回列表