包装盒破损纸板缺陷检测数据集:VOC与YOLO格式实战
简介在工业视觉与目标检测应用中数据质量往往比模型结构更决定项目成败。缺陷检测作为智能制造的核心环节依赖高质量标注数据来训练可靠模型。然而公开数据集多集中于钢材、织物等领域包装纸板场景的样本严重缺失。本文从数据采集、标注规范到格式转换系统介绍了如何构建一套可用的目标检测数据集。针对纸箱破损检测采用单类别标注降低标注歧义并同时提供VOC与YOLO两种主流格式便于在不同框架下直接训练。通过YOLOv8实测验证该数据集在缺陷定位任务上展现出良好效果。无论是从事包装检测的工程师还是刚接触YOLO训练的学习者都能从这套数据集中获得从数据到模型落地的完整参考。 做了这么多年的工业视觉项目我最大的体会就是算法模型反而是最好解决的部分真正决定项目生死的是数据。尤其是包装盒破损纸板这一类的缺陷检测找遍了开源数据集基本没有能直接用的大多数公开数据都是钢材表面、织物、PCB板这类拿到纸箱场景里迁移效果很差。所以我干脆自己从产线现场攒了一套包装盒破损纸板缺陷检测数据集一共1055张单类别同时整理成VOC和YOLO两种格式打包成7z方便传输和解压。这套数据集现在已经在几个纸箱质检项目里实际跑过训练模型效果可直接落到产线初步试用。如果你正在做包装制品外观检测、纸板缺陷识别或者刚接触YOLO想找一份“拿过来就能训练”的真实数据集又或者被各种格式转换折腾过这套数据值得你花几分钟看完下面的内容。我主要讲几个部分数据集的定位和为什么这么设计、采集和标注的详细过程、VOC和YOLO两种格式怎么生成和互转、7z压缩和发布时要注意的坑以及我用YOLOv8训练这套数据时踩过的坑和最终效果。1. 内容整体设计与思路拆解1.1 为什么要做单类别、只有1055张的数据集先说结论这不是凑数是刻意控制。包装盒破损检测在产线上的需求非常集中大多数时候只要判断“这个箱子能不能继续用”或者“有没有破损”并不需要区分是裂纹、破洞还是边缘撕裂。做多分类当然信息更丰富但实际带来的问题是标注成本翻倍、类别间边界模糊以及模型在“压痕”和“裂纹”之间反复摇摆。我早期试过把破损细分成“破洞、裂纹、撕裂、压痕”四类结果标注员之间的一致性很差同一张图不同人标注的类别都不一样模型训练出来精度一塌糊涂。后来干脆合并成单类别所有“不该出现在正常纸箱上的结构破坏”全部算破损训练难度立刻降了一个量级。1055张也是一个经过考量的数字。工业缺陷检测和通用目标检测不一样场景高度固定打光、角度、相机位置基本不变所以不需要像COCO那样要几十万张。对于单一类别、单一场景的检测任务1000张左右的图片已经能支撑第一版模型的训练配合数据增强和预训练权重迁移能实现一个可以上线的基线模型。如果你想追求更好的泛化能力这套数据还可以继续扩充但初始5000张内性价比都很低。1.2 为什么VOC和YOLO两种格式都要给很多视觉工程师拿到数据集第一件事就是转格式VOC转YOLO、YOLO转COCO转来转去经常因为坐标归一化算错、类别编号对不上导致训练报错甚至模型训练出来是废的。这份数据集同时提供VOC和YOLO两种格式目的就是让你少踩一次格式转换的坑。VOC格式是目标检测领域的老牌通用格式标签信息全部放在XML里人眼可读性强用labelImg打标签保存出来就是这个结构后续想转成COCO、JSON或者其他自定义格式都比较方便。YOLO格式则是现在使用量最大的训练格式Ultralytics YOLOv5、YOLOv8、YOLOv11等框架都直接读取这种格式标签是纯文本每行一个目标五个数字分别是“类别编号、归一化中心点x、归一化中心点y、归一化宽度、归一化高度”。两种格式各有各的适用场景放到一起发布适合不同框架的用户直接使用不需要再折腾转换脚本。1.3 这套数据到底能解决什么问题它的直接用途是训练一个检测模型输入一张纸箱或纸板图像输出破损位置的边界框。应用场景包括流水线纸箱外观检测相机拍完传送带上的纸箱模型框出破损位置供剔除或人工复核仓储物流的来料质检纸箱入库前检测破损避免破损包装导致内部产品损坏引发客诉纸板出厂质检原纸板在出厂前检测表面和边缘破损减少不良品流出YOLO目标检测学习作为单类别、场景聚焦的数据集用来练习YOLO训练流程、数据增强、模型部署非常合适2. 数据采集与预处理细节2.1 采集设备和拍摄条件怎么选数据采集阶段决定了数据集质量的80%。我用的是普通工业面阵相机加定焦镜头分辨率500万像素2592x1944左右实际拍摄时会把纸箱放在固定的工装台上相机垂直向下俯拍拍摄距离保持在60到80厘米保证一个纸箱表面占据画面主体。如果你手头没有工业相机用手机拍摄也能凑合但建议固定机位、固定俯仰角不要手持随意拍。纸板材料本身的反光特性需要专门关注。瓦楞纸箱表面粗糙漫反射为主反光不像金属那么严重但如果是覆膜纸箱或者光面纸板直射光源会造成高光过曝破损位置的纹理细节全部被淹没。我实际测试下来用45度角方向打光对破损检测最友好既不会形成大片反光又能在破损边缘形成阴影增强缺陷的视觉对比度。光源用普通的LED灯板就可以加一层扩散板效果更好能去掉硬阴影。2.2 破损样本怎么拍才有效这里有一个新手很容易忽略的细节破损缺陷的形态分布极不均匀。运输过程中产生的破损有的发生在纸箱的角上有的在侧面中部有的是受潮变软后被压塌的整片凹陷有的是被尖锐物体戳出的洞。如果只对着同一类破损疯狂拍摄模型学到的特征会非常单一换条产线立刻失效。我当时的做法是分渠道收集样本。跑了几家纸箱厂和电商仓库专门找那些运输中受损、退货、落地时压坏的纸箱人为按照“戳、挤、撞、划、水浸后破损”等几种方式制造破损样本。总共覆盖了四类常见的破坏模式贯穿型破洞边缘有纸屑和毛边形状不规则边缘撕裂纸箱折边或压线位置的裂口表面破损起皮表层纸磨破或胶带撕扯带走表层纤维压溃型破损纸箱被重物压塌角落破裂覆盖率比单纯数量更重要这一点在后来的训练效果中体现得很明显。模型对没见过的新破损模式几乎都能检测到就是采集阶段覆盖度做的比较扎实。2.3 初筛与去重影响精度的隐藏因素拍完的照片不是全都能进数据集初筛非常关键。我筛掉了三类图第一种是明显模糊的凡是边缘轮廓看不清、破损纹理不清晰的直接删掉。第二种是破损占比过小、肉眼都很难辨别的极端小目标这类图像在标注时容易产生争议也会拉低模型整体表现。第三种是整个画面里纸箱占比太低、背景杂物太多的这类图对模型训练就是纯噪音。还有一个容易踩坑的是去重。如果相机固定、纸箱破损位置固定连续拍几十张画面几乎一模一样这些相似度极高的图片会让验证集形同虚设模型等于用训练数据在验证mAP虚高但实际泛化能力很差。我利用简单的图像哈希算法去重连续帧相似度超过90%的只保留一张确保1055张里面有足够多的场景和形态变化。3. 标注规范与VOC/YOLO格式实战3.1 破损类缺陷的标注边界怎么定缺陷标注和普通物体标注最大的区别是边界模糊。一张桌子、一个人的边界非常明确但一个破损“到哪里算是破损的边缘”不同人理解完全不同。我在这套数据集里定了一个标注规范所有标注人员都按照这个标准执行只要纸板出现穿透、断裂、起皮、破洞等结构损伤就标注为defect边界框框住损伤区域的完整外接矩形不需要紧贴损伤边缘留像素级余量如果一个破损区域面积太小不足以在最小标注尺寸大约覆盖32x32像素以上下被识别就放弃不标压痕、凹陷但没有破裂的情况不算破损不标注这个规范执行下来标注的一致性明显提高。有些标注员习惯把背景也框进去一点有些标注员又框得太紧训练的时候框的大小噪声就会很大。所以规范里明确框可以略大但不可以漏。3.2 用labelImg生成VOC标注文件我标注用的工具是labelImg这个工具虽然老旧但非常稳定尤其是在制作VOC格式数据时它原生支持PascalVOC XML输出不需要额外写插件。安装可以直接用pip安装pip install labelImg启动后在界面左侧选择“PascalVOC”格式然后用矩形框把破损区域框出来类别命名为defect一张一张标注保存。保存产生的XML文件记录了图片路径、图片尺寸、每个目标框的坐标和类别名这样VOC格式就生成了。标注过程中有一个操作细节值得注意标注框的坐标值是整数像素labelImg生成的XML中xmin、ymin、xmax、ymax都是原始像素坐标不需要做任何归一化处理因为VOC格式的设计就是原始坐标。不要再自己手动做归一化又写回XML这样就多此一举了。标注完一圈大概需要检查一遍XML文件是否都能对应到图片labelImg偶尔会出现保存失败的情况。我是用一个Python脚本遍历一遍所有XML检查xmin xmax、ymin ymax、坐标没有超出图片宽高以及图片路径对应的文件真实存在这一步叫标注自检必须在转格式之前完成。3.3 VOC转YOLO坐标归一化公式与脚本VOC转YOLO是使用频率最高的一种转换需求核心就是把像素坐标转成归一化中心点坐标和归一化宽高。转换公式如下xc (xmin xmax) / 2 / width yc (ymin ymax) / 2 / height w (xmax - xmin) / width h (ymax - ymin) / height其中width和height是图片的原始宽度和高度。为什么要归一化因为YOLO系列训练时会对图片做缩放和填充归一化的坐标值在图片缩放后还能直接对应到原图上的位置这也是训练框架要求这种格式的根本原因。给一个可以直接批处理转换的Python脚本我当初就是拿这个脚本一次性把所有VOC XML转成YOLO txt省了很多时间import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_file, width, height, class_list): tree ET.parse(xml_file) root tree.getroot() boxes [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_list: continue cls_id class_list.index(cls_name) xmlbox obj.find(bndbox) xmin int(xmlbox.find(xmin).text) ymin int(xmlbox.find(ymin).text) xmax int(xmlbox.find(xmax).text) ymax int(xmlbox.find(ymax).text) x_center (xmin xmax) / 2.0 / width y_center (ymin ymax) / 2.0 / height box_w (xmax - xmin) / float(width) box_h (ymax - ymin) / float(height) boxes.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) return boxes # 使用示例遍历所有XML生成同名txt xml_dir Annotations txt_dir labels os.makedirs(txt_dir, exist_okTrue) class_list [defect] for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() width int(root.find(size/width).text) height int(root.find(size/height).text) lines voc_to_yolo(os.path.join(xml_dir, xml_file), width, height, class_list) txt_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(txt_dir, txt_name), w) as f: f.write(\n.join(lines))用这个脚本需要注意class_list的顺序决定了类别编号YOLO格式中每一行的第一个数字就是该类别在class_list中的索引。整个数据集里只有defect一个类别所以索引一直是0。如果后续增加类别必须在class_list中固定顺序且和训练时的data.yaml保持一致否则就会发生类别错乱。3.4 标注质量自查与修正方法标注质量对最终模型效果的影响怎么强调都不为过。有一次我赶时间标注完没有做检查直接转了格式去训练结果mAP只有30多。后来一查发现训练集里几十张图标注框明显偏移破碎边缘没有框进框里还有几张图类别名拼写不一致导致YOLO的类别文件顺序和标签内容对不上。这种错误非常隐蔽模型训练时的loss曲线也能看到异常但新手很容易忽略。推荐一个自查方法把标注框直接画到图片上叠加显示人眼扫一遍所有图片。这样能快速发现标注框是否严重偏移、是否覆盖到无关背景、是否有明显的漏标。代码很简单用OpenCV循环绘框把标注信息和图片叠在一起输出一个preview目录然后挑着看就行。这套数据集的1055张图我全部人工过了两遍第一遍看漏标第二遍看框的大小和边界是否离谱。提示标注数据时给每个标注成员固定负责固定的图片子集并用同一套标注规范约束可以减少不同人的主观差异性。如果项目周期允许再安排另一个人做交叉审核效果更稳。4. 数据集目录结构、7z压缩与发布要点4.1 拿到压缩包后先看目录结构这套数据集的7z压缩包解压后目录结构分两层VOC目录放VOC全套格式YOLO目录放YOLO全套格式。两种格式内部又按训练需要做安排。VOC格式的目录结构VOC/ ├── Annotations/ # 所有XML标注文件 ├── JPEGImages/ # 所有PNG/JPG图像 └── ImageSets/ └── Main/ ├── train.txt ├── val.txt ├── trainval.txt └── test.txtAnnotations和JPEGImages里面的文件名一一对应比如img_0001.jpg对应img_0001.xml。ImageSets/Main目录下的train.txt、val.txt等文本文件每一行只写图片文件名不带后缀这是VOC框架的通用格式。划分比例采用7:2:1的比例随机划分既满足训练需求也给测试集留下了100多张的数据量。如果你训练时需要不同的划分可以直接自己重新生成这些txt原始标注文件都没有变。YOLO格式的目录结构YOLO/ ├── images/ │ ├── train/ # 训练集图片 │ ├── val/ # 验证集图片 │ └── test/ # 测试集图片 ├── labels/ │ ├── train/ # 训练集标签txt │ ├── val/ # 验证集标签txt │ └── test/ # 测试集标签txt ├── train.txt # 所有训练图片的路径列表 ├── val.txt └── test.txtYOLO格式中每张图片的同名txt文件放在labels目录下文件内容就是前面转换脚本生成的那几行文本。这个目录结构可以直接被Ultralytics YOLO的配置读取也方便你自己写Dataloader。4.2 7z压缩和校验不要忽略这些细节用7z格式而不是zip最直接的理由是压缩率更高。这份数据集里面的图片主要以JPG为主7z在极限压缩下比zip默认压缩级别能再压掉30%-40%的体积。原始图片加标注文件大概有800多MB压成7z之后大概只有500多MB在线传输和存储都更方便。压缩的时候我建议打开7-Zip选择“添加到压缩包”格式选7z压缩级别选“极限”字典大小不要设置太大默认值或32MB就可以再往大对收益基本没有。如果是个人用不需要用分卷压缩。但如果你的网络环境上传大文件容易失败或者接收方有下载时长限制可以考虑分卷成100MB一段。我这里没有做分卷完整7z包更省心。压缩完成之后一定要做完整性校验。7-Zip有一个“测试压缩包”功能快捷键是AltT会逐个文件测试CRC校验值能发现压缩包是否损坏。我从数据发布角度考虑还会把整个包的SHA-256校验值写出来下载后对比一下确保拿到的是完整无损坏的文件。发布给别人之前还有一件事别漏了README文件。我在数据集的根目录放了一个简短的README把以下内容都写清楚数据集的用途和适用场景标注类别名及含义训练集/验证集/测试集划分比例每种格式的目录结构说明目标检测模型的配置示例训练时的注意事项比如图片分辨率、类别编号这个文件虽然不起眼但能大大节省使用者的理解成本也减少花式提问。4.3 发布前的检查清单把数据集打包准备发布前我会按下面这个清单逐条过一遍全部通过才敢往外发所有图片文件名和标签文件名一一对应没有多余文件也没有缺失文件每张图片的标注框坐标都在图片范围内所有XML和txt文件不是空文件至少一个标注对象YOLO标签的行数、类别索引和图片上的实际目标一致划分后的训练集、验证集、测试集没有交叉压缩前用代码随机抽10张图可视化检查压缩后测试解压一遍并跑一次YOLO训练确认能正常迭代这个检查清单看着简单但很多公开数据集做得并不好。我之前从其他地方下载数据集训练时经常遇到空标签的问题找半天发现是XML里difficult标记被错误地当成了负样本最后生成的训练配置一团糟。现在自己做数据发布这些坑都记下来了。5. 用YOLOv8实测数据质量与训练结果复盘5.1 数据集配置与训练参数Ultralytics YOLO是目前训练这套数据最省事的框架。用的时候先确认数据集的YOLO目录格式然后在项目根目录配置一个data.yamltrain: YOLO/images/train val: YOLO/images/val test: YOLO/images/test nc: 1 names: [defect]这里有个细节容易被忽略train、val等路径如果写相对路径路径要基于你执行训练命令时所在的目录。为了避免路径问题建议直接用绝对路径或者把数据集放在固定的目录下再用相对路径。训练命令很简单yolo detect train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch16我用的是yolov8n作为起始权重因为预训练权重已经学习了通用视觉特征自己的数据集上只需要微调就能快速收敛。如果你的场景和自然图像差异很大比如特殊的打光、特殊的视角可以考虑随机权重从零训练但通常微调效果更好、收敛更快。5.2 训练结果怎么看关键指标和调参方向在这套1055张的数据集上用yolov8n训练100轮最终验证集上的mAP50大约在0.87左右mAP50-95大约在0.65左右。这个成绩对单类别缺陷检测来说已经足够支撑产线初步试用。看训练曲线有一个经验如果前10轮loss下降很快后面趋于平缓说明数据质量是好的。如果loss震荡很大或者迟迟不收敛先检查标签有没有问题再考虑调学习率。最常见的问题不是模型结构不行而是标签里面出现了错乱类别或者空标签。针对不同的产线需求这里给出参数调整建议如果产品线速度快对速度要求高、精度要求一般用yolov8n或者yolov8simgsz可以降到416或480如果瑕疵很小、需要精确检测小目标建议imgsz调到640或更高同时降低置信度阈值默认值因为小目标往往容易被低置信度滤掉如果出现明显的过拟合训练集mAP高、验证集mAP低降低epochs增加数据增强和dropout5.3 落地部署时常见的坑训练完了离真正上线还有一段距离。这里总结几个我在缺陷检测落地时遇到过的问题和排查思路。第一个坑是训练集背景和产线现场背景差异过大。训练数据里我用了比较干净的纸箱画面到了产线上背景里出现了传送带金属架、工人手套、附近的包装材料等模型误检率一下子提高。解决办法有两类一是采集的时候刻意加入一些现场背景干扰的图片二是训练后加一个ROI区域过滤只在纸箱主体区域做检测。第二个坑是光照差异。同一个纸箱在晴天和阴天、在车间和仓库颜色和阴影完全不同。如果数据采集时没有覆盖不同光照条件模型的鲁棒性会差很多。这个数据集的主力采集条件以室内恒定光为主但我在拍摄时有意识地引入了不同亮度和角度让模型不至于对光线过度敏感。第三个坑是缺陷尺度的分布。破损缺陷不像人、车那样有相对固定的尺度范围一个小破洞可能只有20像素一个整面塌陷可能占据半张图。YOLO系列对小目标的检测能力天然弱一些所以我建议做小目标增强在训练时把图像切成小块让模型看到更多小尺度的缺陷或者直接用yolov8-seg做分割效果可能更好。6. 常见问题与排查技巧实录这个部分把我在制作、分享、使用这份数据集过程中遇到的高频问题整理成一个速查表方便大家直接对照排查。现象原因解决办法训练时提示找不到标签文件txt和图片文件名不完全一致或目录路径错误统一文件名前导部分检查文件扩展名和目录映射训练时标签全为空YOLO标签txt内容为空或标签文件没有放到正确的labels目录遍历检查所有txt文件内容非空且坐标在0到1之间训练时类别数不对data.yaml的names列表数量和标签中的类别索引不匹配打开标签txt查看最大类别索引调整names列表转换坐标后框严重偏移归一化时除以了错误的宽度高度比如PIL读图的宽高顺序搞反了检查图片尺寸读取方式OpenCV和PIL的宽高顺序不同7z解压时报文件头损坏压缩包下载不完整或传输过程中损坏用7-Zip测试压缩包重新下载并对比SHA-256训练mAP虚高但实测很差数据集划分有交集验证集包含了训练集相似图片用图像哈希去重重新划分数据集并在制作时注意拍摄角度、光照多样性模型对某类破损漏检该类破损在数据集中占比太少增加该类样本数量而不是单纯增加总数据量单独挑一个最容易被忽略的问题详细说data.yaml中train和val路径指向同一个目录会导致严重的数据泄漏。有人为图省事把全部图片放在一个目录下训练和验证都指过去结果训练时每个epoch的val就是train本身mAP高到离谱一部署就翻车。如果你用的是Ultralytics YOLO它会自己读取images和labels下的train、val、test子目录所以目录结构本身就是划分不要在yaml里偷懒指向同一处。还有就是不同训练框架对标签格式的容忍度不同。Ultralytics YOLO对标签要求很严格坐标必须是归一化的浮点数类别编号必须是整数文件内容不能有多余空格。如果这个数据集里某些标签文件有末尾多余空格有的框架会强行报错有的会忽略但为了稳妥起见我都做了统一处理。最后再说一个使用上的小建议如果你拿这份数据集只是为了练手或者做毕设实验建议不要直接上来就全量训练。先取一部分训练集比如200张图快速跑通整个训练和推理流程确认数据、标签、配置都是通的再全量训练。这能帮你把环境问题跟模型问题解耦出错的时候更容易定位。我的经验是一份数据集最大的价值不在于它有多大规模而在于它能不能帮你把一条数据链路跑通从图片拍摄、标注、格式转换、压缩存储、训练测试到最终部署。有很多人天天研究最新的模型结构却连自己手头的数据集质量都不清楚这是很可惜的。先把数据这一关过了模型效果才能真正立得住。本文还有配套的精品资源点击获取