鸡蛋破蛋检测数据集:VOC与YOLO双格式目标检测实战
简介在工业质检与自动化分拣场景中目标检测技术正逐步替代传统人工目检成为提升产线效率的关键手段。而高质量的数据集是训练可靠模型的基础尤其对于农副产品分级这类细分任务公开可用的标注数据极为稀缺。本文围绕鸡蛋破蛋检测这一典型小样本视觉任务介绍了一套包含792张图像、2个类别的专用数据集同时提供VOC与YOLO双格式标注。从数据采集、边界标注规则到YOLOv8训练流程、数据增强策略及常见踩坑经验系统梳理了从模型训练到产线部署的完整链路。该数据集复用性强可直接用于验证算法可行性也适用于传送带场景下的鸡蛋破损识别、禽蛋分级设备开发及食品质检系统原型搭建。通过合理运用小样本学习与迁移学习技巧即使是规模有限的数据也能获得满足产线初步验收的检测精度为相关领域的工程实践提供有效参考。 做禽蛋自动化分拣的朋友应该都有体会破蛋检测这个环节水很深。我去年在产线上被鸡蛋输送链的碎裂率折腾得够呛才开始认真上手搞这套鸡蛋破蛋检测数据集。市面上的公开数据集少得可怜几乎没有针对蛋壳破损的专门数据要么是通用物体检测要么是农产品分级但根本没细分到裂纹这种小目标。所以我干脆自己整理了一套VOC和YOLO双格式792张图片2个类别专门用来训练破蛋检测模型。这套数据集解决的核心问题很简单在传送带场景下用目标检测算法把破损蛋从完好蛋里挑出来替代人工目检或者作为产线质检的前置筛选。它的适用范围很明确做禽蛋分级设备、养殖场自动化改造、食品加工厂质检系统的视觉工程师或算法工程师都可以直接拿它来验证算法、训练模型、跑通产线流程。792张图不算大但作为小样本下的算法可行性验证和工程原型完全够用。下面我会把这套数据集的来龙去脉、标注规则、格式细节、训练流程和踩坑经验全部拆开讲一遍尤其是双格式的转换逻辑和小样本训练时那些折腾人的问题都给你捋清楚。1. 项目背景为什么破蛋检测需要一套专用数据集1.1 破蛋检测在禽蛋产线上的真实痛点先说说我在产线这边看到的实际情况。鸡蛋从养殖场收集过来之后要经过清洗、风干、裂纹检测、分级、包装这一串流程其中裂纹和破损几乎是每个环节都会冒出来的问题。运输颠簸、设备落差、蛋托卡滞甚至蛋壳本身的厚度差异都会让破损率居高不下一般统计下来在1%到3%之间波动碰上批次质量差的时候能冲到5%以上。传统的人工目检老师在产线边上盯一天眼睛疲劳之后漏检率会明显上升。而普通工业相机加规则的方案呢处理裂纹这种低对比度特征又很吃力——鸡蛋表面本身有光泽光照一变化裂纹跟正常纹理在图像上根本分不开。再加上蛋壳颜色有褐壳、白壳、浅褐壳之分深浅不一规则算法写起来简直是要命。我试过用传统的边缘检测加形态学处理去做裂纹识别效果非常不稳定。光照稍微偏一点或者鸡蛋表面有水渍误检率就飙到没法看。后来转向深度学习目标检测发现了一个更麻烦的问题没有数据。公开数据集里确实有一些带鸡蛋的图片但几乎没有专门标注了“破损”和“完好”这两种状态的高质量样本。这就逼着我自己动手整理数据集。破蛋检测的表面看是算法问题本质其实是数据问题尤其是对工业场景来说一套贴合产线实际情况的标注数据比模型结构本身值钱得多。1.2 VOC和YOLO双格式的设计思路数据格式的选型其实挺讲究。VOC格式是XML标注文件在标注工具和开源生态里吃得开LabelImg、Roboflow、各类可视化脚本对它支持得最好。而YOLO格式是TXT归一化标注直接喂给YOLOv5、YOLOv8这些主流检测框架训练时不用再做额外转换。一开始我用LabelImg标注时输出的是VOC格式因为方便检查标注框是否贴合目标。但训练YOLO模型时又需要YOLO格式。两个格式来回倒腾纯靠手工转换就太费劲了所以我干脆把数据集做成双格式发布一份XML放在Annotations目录一份TXT放在labels目录图片放在同一套文件名体系下。谁拿到手上想用哪个格式直接用省去中间转换的麻烦。双格式还有个隐藏的好处统一的文件夹结构方便做二次开发。比如有些朋友想转成COCO格式或者想用mmdetection训练基于VOC的XML和基于YOLO的TXT都能作为中转改个脚本就行。这也是我决定把数据集以双格式发布的核心原因工程上可以少绕很多弯路。1.3 792张图片和2个类别的规模考量792张图片2个类别这个规模放在目标检测数据集里确实不算大。但破蛋检测这个场景有它的特殊性目标单一、结构固定、背景相对可控。相比那种需要海量数据的通用检测任务小样本加上合理的增强策略已经足够跑通并验证算法可行性。我在这792张图里刻意控制了场景和类别的覆盖范围。图片主要来自传送带固定工位的俯拍视角也就是产线上实际部署检测相机的角度同时补充了一部分手持设备在不同距离、不同角度拍的近景图目的是让模型对光线变化和拍摄距离有一点鲁棒性。2个类别分别是完好蛋和破损蛋边界定义得比较清楚这个放在后面细说。如果按数据增强之后的等效数据量来算792张原图配合Mosaic、随机翻转、HSV扰动这些常见增强训练出来的模型在小批量验证集上已经能达到产线初步调试验收的区间。对于想要验证“深度学习能不能解决我这个蛋品分拣问题”的工程师来说这套数据集的样本量是够用的。2. 数据集构成与标注逻辑详解2.1 图片采集场景与覆盖策略做数据集的第一个教训就是一定要贴着产线真实工况采集不要为了省事在实验台上摆拍。我这边采集场景分为三类一类是模拟产线传送带俯拍相机固定在蛋托正上方约40厘米处光源采用两侧条形LED灯第二类是分拣台上的摆放状态模拟人工上料环节第三类是手持拍摄的近景特写专门针对裂纹细节。这样设计的原因是破蛋检测的实际部署环境不会只有一个角度。传送带上蛋的位置可能略有偏移灯光可能受环境光干扰鸡蛋大小也不一样。如果只在一个固定角度采集模型在测试时遇到稍微变一下的姿态就会掉点。近景特写虽然不会直接作为产线主输入但我用来做数据增强的素材来源也提高了模型对“小目标裂纹”的敏感性。品种覆盖上我刻意混入了褐壳蛋、粉壳蛋和白壳蛋破损类型也尽量覆盖了细裂纹、大裂纹、凹陷破碎、蛋液渗出这几种典型状态。因为不同蛋壳颜色在图像上的纹理差异很大模型不能只见过一种褐壳蛋到了白壳蛋产线上就失效。2.2 二类别标注的边界规则标注规则是整个数据集质量的核心这里我要重点展开说。两个类别我用的是“完好蛋”和“破损蛋”来命名。很多朋友拿到数据集后问为什么不用“裂纹蛋”和“正常蛋”因为“破损”的语义范围比“裂纹”更宽既包含细裂纹也包含凹陷和蛋液渗出实际产线上需要剔除的本来就是所有“非完好”状态的蛋。标注框的规则是一个蛋一个框框要贴合蛋体边缘尽量不包含蛋托或其他背景。破损蛋的标注尤其要注意如果蛋壳碎了一块框要框住整个蛋体而不是只框碎裂区域。因为后期如果要做剔除动作机械手需要知道整个蛋的占位范围只框裂纹区域会导致定位偏差。比较难处理的是那些“轻微裂纹”的边界。裂了一条几乎看不见的细纹算不算破损我的标注原则是只要在图像上能被人眼明确识别出裂纹线就标成破损蛋如果看着像又不太确定宁可标成完好蛋也不要制造模糊样本。因为模糊标注会让模型学到的特征边界是毛的训练起来非常痛苦。如果你用这套数据集做二次标注或扩充我建议延续同样的原则保持标注口径一致。2.3 VOC与YOLO格式目录结构与转换方法数据集发布时的目录结构是这样的egg_crack_dataset/ ├── images/ │ ├── train/ # 600张 │ ├── val/ # 120张 │ └── test/ # 72张 ├── annotations/ # VOC格式XML与images同名 │ ├── train/ │ ├── val/ │ └── test/ └── labels/ # YOLO格式TXT与images同名 ├── train/ ├── val/ └── test/训练集、验证集、测试集按大约8:1:1划分同来源的图片不会跨集合避免数据泄露。VOC格式的XML关键结构长这样每个目标对应一个object节点annotation foldertrain/folder filenameegg_001.jpg/filename size width1920/width height1080/height depth3/depth /size object nameintact_egg/name bndbox xmin420/xmin ymin260/ymin xmax580/xmax ymax410/ymax /bndbox /object /annotationYOLO格式的TXT就简洁很多每行代表一个目标格式是类别ID 归一化中心点x 归一化中心点y 归一化框宽 归一化框高。类别ID从0开始0对应完好蛋1对应破损蛋。比如刚才那个框转换出来就是0 0.2604 0.3102 0.0833 0.1389转换公式很简单中心点x等于xmin加xmax除以2再除以图片宽度框宽等于xmax减xmin除以图片宽度y方向同理。这里有个我踩过的坑XML里的坐标如果越界了比如xmax比图片宽度还大转换出来的归一化值就会大于1YOLO训练直接报错或者忽略这个框。所以转换脚本里最好加上坐标裁剪把所有坐标钳制在图片范围内。3. 用这套数据集训练YOLOv8的完整流程3.1 环境准备与数据集目录组织拿到数据集后第一件事不是急着训练而是把目录结构和配置文件理顺。我用的框架是YOLOv8Ultralytics版本Python环境建议3.9以上PyTorch 2.0以上。硬件方面因为图像分辨率有1080p显存建议8GB以上推荐GTX 3060或者更好的卡不然batch size会受限制。首先在你的项目目录下建好数据文件夹把images、annotations、labels三个目录放进去。如果目录名和我的不一致一定要改成一致否则后面YOLO读不到文件会报错。然后写一个data.yaml配置path: /path/to/egg_crack_dataset train: images/train val: images/val test: images/test names: 0: intact_egg 1: cracked_egg这里有个容易忽略的细节YOLO在训练时会自动去labels目录里找与图片同名的TXT文件。也就是说如果你的labels目录结构是labels/train/egg_001.txt那么配置里的train只需要写images/trainYOLO会自动把images替换成labels去读取标注。所以双格式数据集的目录命名必须保持高度一致不然后续训练会因为路径对不上而各种报错。3.2 训练参数设置与数据增强策略训练参数的设置小样本场景和通用大样本场景差别很大。792张原图在YOLO眼里属于小数据稍微不加控制就过拟合。我对比了几组参数之后最终锁定了一套比较稳的配置yolo detect train \ modelyolov8n.pt \ datadata.yaml \ imgsz640 \ batch16 \ epochs200 \ patience30 \ lr00.01 \ augmentTrue \ mosaic0.5 \ fliplr0.5 \ scale0.3模型我刻意选了yolov8n而不是更大的s或m。因为在破蛋检测这种目标单一、类别少、场景简单的任务上小模型已经足够拟合推理速度还快产线上一秒钟要处理几十帧模型大了反而拖后腿。如果用yolov8m跑mAP提升有限但推理时间几乎翻倍完全不划算。增强策略是这条赛道最考经验的地方。Mosaic增强对提升泛化能力很有帮助但对破蛋检测来说如果mosaic比例太高被拼接后的鸡蛋图像会被压缩变小裂纹细节反而糊掉。我把mosaic设为0.5保留了随机翻转和轻微缩放没有开旋转增强。旋转对蛋体检测来说不太合理因为实际产线上蛋的姿态虽然会变但相机视角基本固定过强的旋转增强会让模型学到错误的不变性。3.3 训练过程监测与结果评估训练过程中我习惯把YOLO生成的results.csv实时拉出来看。重点关注两个指标验证集mAP50和mAP50-95的变化曲线以及训练集和验证集loss的差值。如果训练集loss一直在降、验证集loss却不降反升说明过拟合已经开始了。我实测下来yolov8n在这种规模的数据集上大约60个epoch左右就能看到mAP50冲到0.85以上后续的epoch提升比较缓慢需要耐心等。训练结束后的评估不能只看一个mAP。我会额外看混淆矩阵和PR曲线特别是假阳性和假阴性的比例。破蛋检测这个场景里漏检一个破损蛋假阴性和误检一个完好蛋假阳性的代价不一样产线上可能前者更严重因为你把一个破蛋放过去了客户会投诉误检一颗好蛋损失的是单颗蛋的成本影响小一些。所以调优时我会倾向于提高recall也就是尽量少漏再通过提高置信度阈值来控制误检。最终我调出来的一套部署参数是conf_thres设为0.35iou_thres设为0.45。这个组合在模拟产线测试中precision和recall能平衡在比较好的区间。如果你那边的客户对漏检更敏感可以适当把conf_thres调低到0.25提高召回率代价是会增加一些误检框。3.4 推理部署与产线集成要点训练完模型之后离真正上产线还有一段路。我一般会先用YOLO自带的导出脚本转成ONNX格式再根据现场设备的算力选择TensorRT或者OpenVINO引擎。导出命令很简单yolo export modelbest.pt formatonnx imgsz640这里有个工程细节导出时imgsz必须和训练时一致否则推理结果会和训练时偏差很大。另外如果现场用的是树莓派或者Jetson这种边缘设备建议用int8量化把模型压到体积更小、推理更快但量化后精度会掉一到两个点需要重新跑一遍验证集确认在可接受范围。产线集成的另一件事是相机的触发和曝光控制。破蛋检测对运动模糊非常敏感蛋在传送带上移动速度快一点拍出来的裂纹就是模糊的模型很难识别。我建议产线的相机曝光时间控制在1/500秒以上必要时加频闪光源补光。数据集里的图片是静止或准静止状态拍的和产线高速运动下的成像质量有差异部署前一定要在真实环境下重新采集一批图片做测试集验证模型的实际表现。4. 常见问题与排查技巧实录4.1 训练loss不降或mAP很低怎么办这是我被问得最多的问题。训练很久loss都不降或者mAP始终在0.3以下徘徊大部分情况不是模型的问题是数据的问题。首先是检查标注框是否正确转换。我见过好几次XML转TXT时类别ID从1开始导致模型把所有目标都当成第二个类别训练出来完全不能用。YOLO的类别ID是从0开始的这个非常容易搞错。其次是检查图片里有没有大量目标重叠。一个蛋和另一个蛋挨得很近标注框互相重叠模型学习时会困惑边界到底怎么划分。如果验证集里mAP50还行但mAP50-95一直很低说明预测框和真实框的重合精度不够通常是因为标注框没有贴紧目标边界或者图像分辨率太低目标太小。可以尝试提高imgsz到960看看效果有没有改善。学习率的设置也值得留意。小数据集上初始学习率太高特别容易发撒。我建议如果发现loss曲线在震荡不收敛把lr0降到0.005甚至0.001然后适当增加warmup epoch让模型先稳定一段再进入主学习阶段。4.2 完好蛋和破损蛋容易误检怎么做这是破蛋检测最核心的难点。刚磕碰过的鸡蛋裂纹细得几乎看不见人眼都要凑近才能辨认模型在640分辨率下丢失细节也很正常。我的经验是分三步解决第一步训练时提高输入分辨率把imgsz从640提到800或960裂纹的像素数量变多了模型学起来难度下降第二步扩充近景特写数据让模型看过“裂纹长什么样”第三步考虑把单类别检测改成多类别细粒度分类比如把破损蛋细分为“细裂纹型”“破碎型”“渗液型”让模型分别学习不同破损样本的特征虽然标注成本上去了但误检率确实会有明显下降。如果还是反复误检就要从成像端找原因。光源角度不对、逆光、反光都会让裂纹和正常蛋壳的光泽混淆。产线调试时建议把裂了纹的蛋放在传送带上试拍几张看看图像里裂纹是否清晰可见。如果人眼看图都觉得吃力的就别指望模型能有多好的表现。4.3 格式转换和路径报错的坑双格式数据集的最大陷阱是图片文件名和标注文件名不一致。比如图片叫egg_001.jpg标注却叫egg_001.xml.txt或者大小写不匹配YOLO训练时就会静默跳过这张图导致训练集实际可用图片数量比预期少很多。我建议在训练前写个简单脚本检查images目录下每张图片是否都有对应的TXT文件缺失的要一次性找出来处理掉。另一个常见坑是Windows和Linux的路径分隔符问题。YOLO在Windows下训练时data.yaml里的path如果用反斜杠有时候会被转义成奇怪字符。统一用正斜杠写路径或者用相对路径能省很多麻烦。还有朋友遇到过转换出来的TXT文件编码问题用记事本打开又保存一遍后变成带BOM的UTF-8YOLO读坐标时把BOM头当成字符解析直接报错。解决方法是转换脚本里统一用utf-8编码写文件不要用记事本手动编辑。4.4 小数据集的过拟合与增强平衡792张图训练YOLOv8如果不做任何控制到第150个epoch左右训练集loss会降到很低但验证集mAP不动这就是典型的过拟合。我的对策是早停patience提前到30别让模型在过拟合区间里磨太久增强强度适中尤其是HSV颜色扰动不要调太狠否则蛋壳颜色被改到不真实模型学到的颜色特征失真。另外一个好用的方法是冻结骨干网络迁移学习。用小数据集微调时前50个epoch锁住backbone只训练检测头让模型先适配任务输出结构再解锁backbone做整体微调。这样做的原因是经过ImageNet预训练的backbone已经学到了很丰富的通用特征我们不需要把它的权重全部打乱重学只要让它适应蛋壳纹理这个特定域就行。在这套数据集上冻结预训练权重从头训练和直接全量微调的差异没有想象中大但如果你的数据集比792张更小这个技巧会非常有用。最后再分享一个我个人实操下来觉得特别重要的细节在数据集的构建阶段务必把采集环境的光照和角度固定住多批次采集时保持一致性。很多朋友扩充数据时越扩越乱今天拿手机拍几张明天换个光源又拍几张最后喂给模型的就是一堆域差异巨大的样本模型泛化反而变差。破蛋检测这种任务场景越“单调”越好把可控变量都控制住模型才有余力去学真正重要的裂纹特征。本文还有配套的精品资源点击获取
