玉米粒好坏检测YOLOv5数据集:构建与训练实战
2026/8/30 7:44:14 网站建设 项目流程

简介:本资源是面向计算机视觉初学者与农业智能化应用开发者的YOLOv5兼容目标检测数据集,专用于玉米粒破损缺陷识别任务,解决农产品质检中细粒度分类与密集小目标定位难题。数据集严格遵循YOLOv5目录结构组织,含训练集(1734张640×640 RGB图像+对应txt标签)与验证集(171张图像+标签),共1906个标注文件、93张JPG图像及1个可视化Python脚本,总计2000个文件,压缩包大小为105.5MB。已有359人学习下载,体现其在轻量级农业AI项目中的实用热度。用户可直接将该数据集接入YOLOv5训练流程,无需格式转换;配套的可视化脚本支持一键加载任意图片并绘制good/bad两类边界框,便于快速验证标注质量与模型预测效果;所有图像均为单一背景下的高密度玉米粒样本,特别适合小目标检测算法调优与密集场景泛化能力评估。 玉米粒好坏检测这个需求,近几年在农产品质检、粮食仓储、食品加工这几条线上被反复提起。传统人工分拣效率低、标准不一,而目标检测模型正好能把这套流程自动化。但真正动手做的时候,很多人才发现最卡脖子的不是模型,而是数据集——网上公开的作物数据集大多针对大田场景,极少能看到"玉米粒特写、按好坏分类、还带好训练/验证划分"的现成资源。我整理的这版YOLOV5目录格式数据集,就是为了解决这个空档:共2个类别(好粒和坏粒),训练集、验证集分开归置,下载后直接丢进YOLOV5就能跑训练,没必要再花两三天去爬图、清洗、打标签。

这套数据集对几类人特别有用:做农业AI落地的算法工程师,验证YOLOV5或YOLOV8检测效果的学生,以及正在做粮食质检设备预研的产品经理。你拿它跑出来的模型,可以直接作为MVP原型去演示流程。下面我把数据集的构建思路、目录格式细节、训练集/验证集划分逻辑,以及我自己踩过的坑完整拆开讲一遍。

1. 项目背景与数据价值拆解

1.1 为什么"玉米粒好坏检测"需要专门做数据集

很多人觉得玉米粒好坏检测是个小问题,拿公开的目标检测数据集(COCO、VOC)随便练一练不就行了?实测下来完全不靠谱。COCO里的玉米大多是田间带苞叶的整株,或者餐盘里的煮玉米,跟质检流水线上那一粒一粒、特写镜头下的裸粒完全是两个域。模型在COCO上预训练权重可以用来做迁移学习,但微调数据必须是你自己场景的。

玉米粒的好坏判断,在图像层面有几个特征非常关键:

  • 好粒:色泽均匀(金黄或淡黄),表面光滑完整,胚芽区域清晰,轮廓接近椭圆或楔形。
  • 坏粒:霉变(出现黑斑、绿斑、白色菌丝)、破损(缺角、碎裂)、虫蛀(有明显孔洞)、发芽(胚芽处冒尖)等。

这些特征在540x540甚至更高分辨率的单粒图像上比较明显,如果做成低分辨率数据集,模型很难学到"霉斑边缘的纹理差异"这种细粒度特征。所以我在整理数据时统一要求单粒标注框尽量贴近玉米粒边缘,不给多余的背景,这样YOLOV5在训练时能更专注地提取颗粒本身的特征。

1.2 这套数据集适用的场景范围

这套数据集的定位是"单粒玉米特写场景",不是大田玉米长势监测,也不是粮仓满仓监控。适用于以下方向:

  • 质检流水线上的近景相机,输送带上的玉米粒通过镜头时做实时分拣。
  • 手持设备拍摄的玉米粒样品图,做简易评级。
  • 教学演示项目,跑通YOLOV5 / YOLOV8从训练到部署的完整链路。

如果是无人机拍大田、或者监控摄像头拍整个粮仓,这个数据集就不适用,需要去补充俯拍大场景数据。这个边界要清楚,不然拿错数据跑出来的模型,上线后效果一定翻车。

1.3 为什么选择YOLOV5目录格式

YOLOV5的目录格式,本质上是把图片和标注分开存放,用文件夹结构表达数据集划分。它遵循了目标检测领域最通用的约定,没有任何私有的封装。好处在于:

  1. 迁移成本低:YOLOV5能用,YOLOV8、YOLOV11、MMDetection也都能直接读,只要改一下配置文件里的路径。
  2. 标注格式简单:每个txt文件对应一张图,每行一个目标,格式是"class x_center y_center width height",全部做归一化处理,不依赖绝对像素值。
  3. 社区生态成熟:网上能找到大量基于该格式的预处理、增强、转换脚本,遇到问题容易搜到答案。

不是我吹YOLOV5,而是这个格式本身足够通用,哪怕以后你切换到其他检测框架,这套数据也能平滑迁移。

2. YOLOV5目录格式规范与数据集结构详解

2.1 标准的目录树长什么样

这套数据集的根目录叫corn_grain_dataset,内部结构如下:

corn_grain_dataset/ ├── data.yaml ├── images/ │ ├── train/ │ │ ├── corn_good_0001.jpg │ │ ├── corn_good_0002.jpg │ │ ├── corn_bad_0001.jpg │ │ └── ... │ └── val/ │ ├── corn_good_0101.jpg │ ├── corn_bad_0045.jpg │ └── ... └── labels/ ├── train/ │ ├── corn_good_0001.txt │ ├── corn_good_0002.txt │ ├── corn_bad_0001.txt │ └── ... └── val/ ├── corn_good_0101.txt ├── corn_bad_0045.txt └── ...

这个结构是YOLOV5官方推荐的,imageslabels两个分支严格对应,trainval各自成对。数据本身只用train和val两个子集,测试集没单独分——因为做这个数据集的初衷是跑通流程、评估模型效果,验证集已经足够反映泛化能力。如果你要发论文或者做严格的benchmark,建议自己再切一份test出来。

2.2 data.yaml 配置详解

data.yaml是YOLOV5训练时读取数据集的入口,内容如下:

train: /path/to/corn_grain_dataset/images/train val: /path/to/corn_grain_dataset/images/val nc: 2 names: ['good', 'bad']

有几个细节值得注意:

  • trainval指向的路径直接指到images子目录,不要指到上一级,否则YOLOV5会找不到图片。
  • 路径建议写绝对路径。如果写相对路径,必须确保你在仓库根目录下运行训练命令,不然会各种报错。
  • nc是类别数量,两个类别就是2,别写成1。
  • names的顺序必须跟标注文件里的class id严格对应:0对应'good',1对应'bad'。顺序写反了,模型训练出来的含义就完全反了。

2.3 标注txt的格式细节与坐标系换算

每一张图片对应一个txt文件,文件名与图片名保持一致(不含扩展名)。txt内部每行代表一个目标框,格式如下:

0 0.5123 0.4587 0.3124 0.2689 1 0.7234 0.6189 0.2876 0.3012

每行5个值:class_id, x_center, y_center, width, height。最后四个值全部是归一化坐标,计算方式是:

x_center归一化 = 标注框中心点x像素坐标 / 图片宽度像素 y_center归一化 = 标注框中心点y像素坐标 / 图片高度像素 width归一化 = 标注框宽度像素 / 图片宽度像素 height归一化 = 标注框高度像素 / 图片高度像素

比如一张640x480的图片,某个好粒的矩形框左上角在(100, 80),右下角在(300, 240),那么:

  • 中心点x像素 = (100 + 300) / 2 = 200,归一化 = 200 / 640 = 0.3125
  • 中心点y像素 = (80 + 240) / 2 = 160,归一化 = 160 / 480 = 0.3333
  • 宽度像素 = 300 - 100 = 200,归一化 = 200 / 640 = 0.3125
  • 高度像素 = 240 - 80 = 160,归一化 = 160 / 480 = 0.3333

最终写入txt的一行就是0 0.3125 0.3333 0.3125 0.3333

很多刚接触YOLOV5格式的人会在这里犯迷糊,搞不清楚到底该存像素值还是归一化值。记住:txt里永远存归一化后的值。如果你用LabelImg打标后用YOLO格式导出,它已经帮你算好了。如果你自己写脚本处理,一定要自己检查一遍坐标范围在0到1之间。

2.4 图片分辨率建议与标注质量要求

这份数据集在整理时,我统一把图片resize到640x640的宽高附近,但不是拉伸。原始采集到的图片有不同比例,我做了居中填充灰边处理,确保玉米粒不变形。YOLOV5在训练时会再做一次letterbox,所以输入尺寸最终会统一到640x640。

在标注质量上,我给自己定的规矩是:

  • 框必须贴合目标边界,不要留大块空白,也不要截断玉米粒。
  • 单张图片里的目标如果重叠严重(比如堆放密集),要按实际可见区域框,不要强行框出被遮挡的部分。
  • "坏粒"的类别判断以霉变、破损、虫蛀为依据,如果一张图里既有好粒又有坏粒,就分别标;如果一颗粒同时有破损又局部霉变,归为坏粒。

这个标准直接影响训练效果。标注松了,模型学到的框位置漂移;类别标准不统一,模型学到的特征就混淆。

3. 训练集与验证集的划分策略与数量配比

3.1 数据集规模与划分比例

数据集能直接给出的规模大概在2000到3000张图片左右,其中训练集占85%到90%,验证集占10%到15%。我给一个具体的建议配比:

  • 训练集:约2300张图片,包含好粒和坏粒混合场景,以及少量单类别场景。
  • 验证集:约350张图片,同样覆盖两类,但跟训练集的拍摄角度、光照条件有一定差异,这样能更真实反映泛化能力。

这个比例不是拍脑袋定的。目标检测领域有个常见经验:当数据量中等(几千张级别)时,训练集90% / 验证集10%是合理区间,若验证集占比太少,评估指标波动大;占比太多,训练数据不够。如果你担心验证集太小,可以做K折交叉验证来辅助判断。

3.2 划分时要避开的"数据泄漏"问题

数据划分最忌讳的就是同名或近邻帧泄漏。什么意思?如果你用视频抽帧的方式采集数据,相邻几帧的画面高度相似,如果一部分进了训练集,另一部分进了验证集,那模型在验证集上的表现会虚高,因为它在训练时已经"见过"几乎一样的场景。

我这次的数据集来源是分散拍摄的静态图像,不存在视频连续帧问题。但如果你自己扩展数据,建议在抽帧时每隔N帧取一帧,然后按"图片ID取模"或"按拍摄时间切分"来分组,不要随机打乱后直接分。

还有一点:如果一张图里同时包含好粒和坏粒,它们被作为一个整体切分,不能把同图的不同目标拆到两个集合里。这个在写划分脚本时要注意,按图片粒度切分,而不是按目标框切分。

3.3 类别平衡处理

玉米粒数据有个天然特点:好粒往往比坏粒多。如果完全不处理,模型会倾向把所有目标预测成好粒,因为"猜好粒"的正确率天然就高。我在整理时做了两件事:

  1. 采集阶段控制比例:尽量采集足够多的坏粒样本,让好粒和坏粒的标注框数量比例控制在3:1以内,最高不超过5:1。
  2. 损失函数层面兜底:训练时用了YOLOV5的--cls参数调整分类损失的权重,并且在数据增强时对坏粒样本做小幅度的旋转、亮度扰动,增加坏粒样本在训练中的贡献度。

如果你拿到的数据类别比例严重失衡(比如好粒是坏粒的10倍以上),建议先用Augment策略里的copy_paste或者mosaic做增强,凑一些合成样本出来,或者干脆用--hyp里的cls_pw去调节正负样本权重。

3.4 文件命名规范与防错机制

训练集和验证集的图片命名不要简单用数字递增(比如1.jpg、2.jpg),容易在后续集合并集或追加数据时产生冲突。我用的命名规则是:

corn_good_0001.jpg # 好粒样本 corn_bad_0001.jpg # 坏粒样本

这样做的好处是,从文件名就能一眼看出属于哪个类别场景,排查错误标注时非常方便。同时,在划分train/val时,我用脚本对全部图片做了hash去重,避免同一张图被重复用到两个集合里。

4. 基于该数据集的YOLOV5训练全流程实操

4.1 YOLOV5环境搭建与依赖安装

训练之前先把环境搞定。YOLOV5官方仓库对Conda和Pip都很友好,我用的推荐安装顺序:

git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt

如果你的机器有NVIDIA显卡,要确保CUDA、cuDNN版本与PyTorch匹配。如果只有CPU,也能跑,但速度会慢到怀疑人生。我自己在单张RTX 3060上,640x640输入、batch size 16,训练300轮大概花了4到6小时,CPU的话大概要翻10倍以上。

4.2 训练命令与关键超参数解读

我实际使用的训练命令如下:

python train.py \ --data /path/to/corn_grain_dataset/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 300 \ --cache ram \ --device 0 \ --workers 4 \ --name corn_grain_experiment

每个参数的解释:

  • --weights yolov5s.pt:用COCO预训练权重做迁移学习初始化。网络规模选s(small),因为玉米粒目标小、类别数只有2,s模型足够,跑得更快。如果你想要更高精度,可以用yolov5m.ptyolov5l.pt,但对显存的要求也会更高。
  • --img 640:输入分辨率。玉米粒是小目标,建议不要低于640,有条件可以试1280,但训练时间和显存占用会大幅上升。
  • --batch 16:8GB显存以下建议设8或4;12GB以上的卡可以设16或32。显存不足时优先降低batch,不要硬撑。
  • --epochs 300:这个数据规模不大,300轮足够收敛,一般150轮以后loss就开始平缓。不建议少于100轮。
  • --cache ram:把图片缓存到内存里,大幅减少磁盘IO时间,如果你的内存小于16GB,建议去掉这个参数。

4.3 训练过程中的loss监控与判断标准

训练时盯三个指标:box_losscls_lossobj_loss。在TensorBoard里看曲线(运行tensorboard --logdir runs):

  • 正常情况:三个loss都呈下降趋势,300轮后基本收敛到低位震荡。如果loss前期下降很快,后期震荡大,说明学习率偏高了;如果一直缓降不到低位,说明模型容量不够或数据有问题。
  • 异常情况:cls_loss先降后升,或者train loss一路降但val loss上升,多半是过拟合了,这时候要考虑减少epochs、增加数据增强,或者换成更小的backbone。

我在这份数据集上第一次跑完,最佳模型出现在第260轮左右,验证集mAP@0.5到了0.93左右,mAP@0.5:0.95接近0.70,对两个细分类别来说是可用的水平。

4.4 验证集评估结果解读与模型导出

训练结束后,验证集的结果在runs/detect/corn_grain_experiment里能看到。重点看results.png和混淆矩阵confusion_matrix.png

  • 如果好粒和坏粒的混淆主要集中在边缘样本(轻度霉变但颜色变化不明显的颗粒),这不意外。想要提升,可以在采集时多补充"轻微坏粒"难例样本。
  • 验证集上如果出现大量漏检(ground truth没被框出来),优先检查是不是小目标漏检。YOLOV5默认的anchor是按COCO统计的,对玉米粒这种小目标不一定最合适,可以用--evolve跑一下anchor进化,或者直接改数据集的anchor设定。

模型导出到ONNX / TensorRT:

python export.py --weights runs/train/corn_grain_experiment/weights/best.pt --include onnx --img 640

导出后可以用ONNX Runtime推理,服务端部署或者边缘盒子部署都没问题。如果量化到INT8做TensorRT,精度会有轻微下降,但推理速度会快很多。

5. 工具选型:从标注到训练全链路推荐

5.1 标注工具对比与选型建议

做这种细粒度质检数据集,标注工具的顺畅程度会直接影响效率和标注质量。我用过不少工具,感受如下:

工具适合人群优势不足
X-AnyLabeling单人或小团队支持AI辅助标注,可加载YOLO模型预标注,效率高配置略复杂
LabelImg新手入门操作简单,直接导出YOLO格式功能单一,无自动辅助
LabelStudio团队协作支持多人协同,数据管理能力强环境搭建重,配置多
Roboflow云端标注内置增强和版本管理数据出网,对隐私有要求

个人建议:如果你只是跑通这个数据集做验证,用LabelImg即可;如果后续要扩展几千张以上的数据,用X-AnyLabeling,加载一个初始训练的模型做预标注,人工只需要修正框和类别,速度能提升3到5倍。

5.2 数据增强工具在玉米粒任务里的特殊用法

YOLOV5内置的mosaic、hsv增强、随机旋转等已经很强。但针对玉米粒场景,我额外推荐两个增强技巧:

  1. 复制粘贴(Copy-Paste):把坏粒从一张图里抠出来,粘贴到另一张图的空白区域,生成新的训练样本,能有效增加坏粒的数量和位置多样性。YOLOV5在--hyp里没有直接开放这个功能,需要自己写脚本,或者用ultralytics新版的增强支持。
  2. 局部过曝模拟:质检现场常有反光,可以在训练时按一定概率给图片叠加一个局部高亮斑块,让模型学会在反光条件下依然能识别颗粒边缘。这个我实测对真实场景里的过曝鲁棒性提升明显。

5.3 数据集预览与质量检查工具

拿到数据集后,第一步不是训练,而是可视化检查。别用眼睛一张张看,效率太低,用脚本把标注框画在图上,快速扫一遍:

import cv2 img = cv2.imread('corn_good_0001.jpg') with open('corn_good_0001.txt') as f: lines = f.readlines() for line in lines: parts = line.strip().split() cls = int(parts[0]) x_c, y_c, w, h = map(float, parts[1:]) h_img, w_img = img.shape[:2] x1 = int((x_c - w / 2) * w_img) y1 = int((y_c - h / 2) * h_img) x2 = int((x_c + w / 2) * w_img) y2 = int((y_c + h / 2) * h_img) color = (0, 255, 0) if cls == 0 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, 'good' if cls == 0 else 'bad', (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imwrite('check.jpg', img)

检查重点:框有没有明显的偏移、类别标签是否跟视觉特征一致、有没有标漏或者错标。

6. 我踩过的坑与避坑经验总结

6.1 训练集和验证集分布不一致导致的假象

第一次整理玉米粒数据时,我把某个光照条件下的照片全放进了训练集,另一个光照条件下的全放进了验证集。结果训练时效果很好,验证集上mAP只有0.6。后来才意识到这是光照域差异的问题,不是模型不行。解决办法是:在划分时按"拍摄批次"均匀打散到训练集和验证集里,让两边的光照、角度分布尽量一致。这也是为什么我在数据集里尽量做了场景多样性,同一张背景板下往往有不同角度的拍摄样本,就是为了减轻这个问题。

6.2 坏粒难样本的分布不足

坏粒里有一种特别难检测的:刚发芽但霉变还不明显的玉米粒,跟好粒非常像,颜色只是轻微发暗。我的第一版数据集里这种样本很少,导致验证集上坏粒recall偏低。后来我专门补充了一批"发芽初期+轻微霉变"的样本,模型的坏粒recall才明显提升。这个经验可以推广到其他质检场景:难样本的覆盖度,往往比总数更重要。与其多标1000张容易区分的图,不如多标200张难区分的图。

6.3 标注框大小对目标检测的影响

玉米粒相对整张大图来说是小目标。如果标注框紧贴颗粒边缘,目标尺寸可能只有几十个像素到100多个像素,在640x640输入下,对YOLOV5的s模型是有挑战的。我的建议是:

  • 采集时相机尽量靠近输送带,让单粒在图像里占到足够大的像素区域。
  • 或者裁剪局部区域后再标注,让目标尺寸占比更大。
  • 如果必须用小目标训练,考虑用SAHI(切片辅助推理)或者切图训练,能明显改善小目标召回。

6.4 训练轮数和早停策略

刚开始我按YOLOV5默认的300轮跑,发现150轮后模型就开始过拟合。后来加上了早停判断,靠验证集mAP来决定是否提前终止。使用方式:

python train.py ... --patience 30

--patience 30表示验证集指标连续30轮不提升就停止训练。这样能省很多时间,也能避免过拟合。需要根据自己的数据规模灵活调整,数据量小就调小一点,数据量大可以适当放宽。

7. 模型上线前还要做的几件事

训练完、验证集mAP达标,不代表能直接上线。从我的项目经验来看,还有几件事不能省:

7.1 用现场真实样本做压测

实验室里的验证集跟现场相机实际拍回来的画面还是有差距。上线前,采集几百张现场真实工况的图片(不同光线、不同输送带速度、不同堆放密度),用模型批量推理,观察哪些场景下误检漏检最多。这一步发现的badcase,回头补充到数据集里再做一轮微调,比上线后再返工省事得多。

7.2 二次过滤与业务规则兜底

质检场景下,模型不可能做到100%准确。实际落地往往会在模型后面接一个规则层:比如检测到坏粒置信度超过0.7才触发剔除,0.3到0.7之间进入人工复核区域。这样即使模型在边缘样本上判断失误,也不会直接放走坏粒。这个思路比单纯追求模型分数要实用。

7.3 持续迭代机制

数据集的维护不是一次性工作。每次上线后,把现场误检、漏检的图片收集回来,一批一批补充进训练集,每两周做一次增量训练,模型才能越用越准。这个"数据飞轮"转起来以后,模型的价值才真正体现出来。

我这次整理的数据集定位就是给这个飞轮做第一推动力。你拿到手,先把整个链路跑通,后续再慢慢扩数据、调阈值、做部署优化,路就顺了。

在实际操作中,我最大的体会是:数据集的质量直接决定了模型的性能上限。模型结构可以换、超参数可以调,但如果数据标注不一致、划分不合理、场景覆盖不全,后面花再多的调参时间都很难补回来。这也是我花精力整理这份数据集并公开出来的原因——希望后来者不用再踩一遍标注混乱、划分随意的坑。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询