玉米黄曲霉素识别数据集:YOLOv8人工标注与训练全流程
2026/9/24 18:20:24 网站建设 项目流程

简介:这份玉米黄曲霉素识别数据集面向从事农业病害检测、粮食安全质检及计算机视觉应用的研究者与开发者,尤其适合需要快速搭建目标检测模型、验证算法效果的技能进阶人群。资源以原始玉米穗图像为基础,采用YOLOv8完成人工标注,验证准确率可达93.8%以上,可用于黄曲霉素污染区域定位、病害分类识别等任务。压缩包共865个文件,包含432张jpg原始图片、432个txt标注文件及1个yaml配置文件,整体约27.58MB,图片与标注一一对应,yaml文件便于直接接入训练流程。内容覆盖镰刀菌穗腐病、赤霉穗腐病等多种玉米病害样本,标注质量经过人工校验,能有效支撑模型训练与评估。目前已有372人学习下载,适合作为病害识别项目的基线数据,帮助读者省去数据采集与标注成本,快速投入模型迭代与效果验证。

1. 玉米黄曲霉素识别数据集:从原始图片到 YOLOv8 人工标注的完整落地路径

玉米黄曲霉素污染是粮食收储环节最头疼的问题之一,肉眼根本分辨不出来,等发现霉变往往已经整仓报废。这个数据集的核心价值在于:用原始玉米粒图片做 YOLOv8 人工标注,把“哪颗玉米发霉了、霉斑在哪个位置”变成可训练的目标检测任务,验证准确率能到 93.8% 以上。它适合三类人:做粮食质检自动化的工程师、拿 YOLOv8 做毕业设计的学生、以及想把视觉检测落到农业场景的算法同学。数据集本身不复杂,但“原始图片 + 人工标注 + YOLOv8 训练”这条链路里,每一步都有容易翻车的地方,下面按实际落地顺序拆开讲。

2. 数据集拆解与 YOLOv8 标注格式的对应关系

2.1 原始图片为什么比增强图更适合做黄曲霉素识别

黄曲霉素在玉米粒上的表现是局部霉斑、颜色从浅黄到墨绿不等,边缘模糊,和正常玉米的胚芽阴影容易混淆。很多公开数据集为了“好看”会做大量亮度增强、旋转、裁剪,结果模型学到的是增强后的纹理,换一批新玉米就崩。这个数据集坚持用原始图片,好处是保留真实光照、真实背景、真实霉斑形态,训练出来的模型迁移到实际产线时不需要再“猜”原始分布。

但原始图片也有代价:样本不均衡。正常玉米粒远多于霉变粒,如果直接丢给 YOLOv8,模型会倾向于全部预测成背景。常见做法是在标注阶段就控制每张图里霉变粒的数量,或者训练时用copy_paste增强把霉变粒复制到正常图上。我一般会先统计一下每类目标的实例数,如果霉变粒占比低于 15%,就在训练配置里把cls损失权重调高,或者用focal_loss替代默认的 BCE。

2.2 YOLOv8 标注格式:从 LabelImg 到 txt 的转换细节

YOLOv8 用的是 YOLO 格式的 txt 标注,每行class_id x_center y_center width height,全部归一化到 0~1。人工标注时常用 LabelImg 或 Labelme,但 Labelme 默认输出 JSON,需要转一道。下面这个脚本是我实际用的转换逻辑,处理了 Labelme 的矩形标注和 YOLO 格式的映射:

import json import os from pathlib import Path def labelme_to_yolo(json_dir, output_dir, class_map): """ json_dir: Labelme 标注文件目录 output_dir: 输出 YOLO txt 的目录 class_map: {'霉变粒': 0, '正常粒': 1} 这种映射 """ json_dir = Path(json_dir) output_dir = Path(output_dir) output_dir.mkdir(parents=True, exist_ok=True) for json_file in json_dir.glob('*.json'): with open(json_file, 'r', encoding='utf-8') as f: data = json.load(f) img_w = data['imageWidth'] img_h = data['imageHeight'] lines = [] for shape in data['shapes']: label = shape['label'] if label not in class_map: continue cls_id = class_map[label] points = shape['points'] # Labelme 矩形只有两个点:左上、右下 x1, y1 = points[0] x2, y2 = points[1] # 确保顺序正确 x_min, x_max = min(x1, x2), max(x1, x2) y_min, y_max = min(y1, y2), max(y1, y2) x_center = (x_min + x_max) / 2.0 / img_w y_center = (y_min + y_max) / 2.0 / img_h width = (x_max - x_min) / img_w height = (y_max - y_min) / img_h # 过滤掉宽高为 0 的脏标注 if width <= 0 or height <= 0: continue lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") txt_path = output_dir / (json_file.stem + '.txt') with open(txt_path, 'w') as f: f.write('\n'.join(lines)) if __name__ == '__main__': labelme_to_yolo( json_dir='./raw_annotations', output_dir='./labels', class_map={'霉变粒': 0, '正常粒': 1} )

逻辑说明:先读 JSON 里的imageWidthimageHeight做归一化分母,再把 Labelme 的两个角点转成中心点加宽高。参数上,class_map必须和后续data.yaml里的names顺序一致,否则类别会错位。width <= 0的过滤是血泪经验,人工标注时手抖拉出零面积框很常见,不滤掉训练时 loss 会直接 NaN。

2.3 数据集划分:训练集、验证集、测试集的比例与坑

YOLOv8 默认按 8:1:1 划分,但黄曲霉素识别这种细粒度任务,验证集太小会导致mAP波动大。我一般按 7:2:1 分,并且保证每个子集里霉变粒的实例数比例接近。划分脚本不要用random.shuffle直接切,要按图片级别切,否则同一张图的目标被拆到训练和验证集,准确率会虚高。

import random from pathlib import Path import shutil def split_dataset(img_dir, label_dir, output_root, ratios=(0.7, 0.2, 0.1)): img_dir = Path(img_dir) label_dir = Path(label_dir) output_root = Path(output_root) images = sorted(img_dir.glob('*.jpg')) + sorted(img_dir.glob('*.png')) random.seed(42) random.shuffle(images) n = len(images) n_train = int(n * ratios[0]) n_val = int(n * ratios[1]) splits = { 'train': images[:n_train], 'val': images[n_train:n_train + n_val], 'test': images[n_train + n_val:] } for split, files in splits.items(): (output_root / split / 'images').mkdir(parents=True, exist_ok=True) (output_root / split / 'labels').mkdir(parents=True, exist_ok=True) for img_path in files: shutil.copy(img_path, output_root / split / 'images' / img_path.name) label_path = label_dir / (img_path.stem + '.txt') if label_path.exists(): shutil.copy(label_path, output_root / split / 'labels' / label_path.name) if __name__ == '__main__': split_dataset('./images', './labels', './dataset', ratios=(0.7, 0.2, 0.1))

参数说明:random.seed(42)保证可复现,ratios按需调,如果霉变粒总数少于 500 个实例,建议改成 8:1:1 并增加训练轮数。注意label_path.exists()的判断,人工标注漏标是常态,缺 label 的图片直接跳过比报错好。

3. YOLOv8 训练环境搭建与黄曲霉素数据集的配置

3.1 Ubuntu 20.04 下 CPU 版本 YOLOv8 环境的最小安装命令

很多同学手头只有 CPU 机器,或者显卡是 GTX 1660 Ti 这种 6G 显存的,跑 YOLOv8 不是不行,但要选对版本和 batch size。Ubuntu 20.04 上我一般用 conda 建环境,避免和系统 Python 打架:

conda create -n yolo_corn python=3.9 -y conda activate yolo_corn pip install ultralytics==8.0.200 pip install torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/cpu

逻辑说明:ultralytics是 YOLOv8 的官方包,8.0.200这个版本对 CPU 推理比较友好,不会强制要求 CUDA。torch的 CPU 版本从官方 index 装,避免 pip 默认源拉到 GPU 版导致依赖冲突。装完用yolo checks验证,如果显示CPU就对了。GTX 1660 Ti 的话把--index-url换成cu118的源,batch size 设 8 或 16,再大就 OOM。

3.2 data.yaml 的写法与类别名映射

YOLOv8 训练前必须有一个data.yaml,指定训练、验证、测试路径和类别名。黄曲霉素数据集一般就两类:霉变粒和正常粒。写法如下:

path: /home/user/corn_dataset train: train/images val: val/images test: test/images names: 0: moldy_corn 1: normal_corn

注意path用绝对路径,train等用相对路径,YOLOv8 会自动拼接。names的 key 必须从 0 开始连续,和标注时的class_id一一对应。如果标注时用了中文类别名,这里要改成英文,否则训练时names解析会报编码错误。我一般会在data.yaml同目录放一个classes.txt,内容就是moldy_cornnormal_corn,方便后续推理时对照。

3.3 训练参数:epochs、imgsz、batch 怎么设才不浪费算力

CPU 训练黄曲霉素数据集,imgsz设 640 就够,再大速度指数级下降。epochs设 100 起步,如果验证集mAP50在 50 轮后还在涨,就加到 200。batch在 CPU 上设 4 或 8,GTX 1660 Ti 设 16。关键参数是patience,设 20 表示 20 轮验证指标不提升就早停,省时间。

yolo detect train \ data=/home/user/corn_dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=8 \ patience=20 \ device=cpu \ project=corn_runs \ name=exp1

逻辑说明:model=yolov8n.pt是最小的 nano 模型,CPU 上也能跑,如果准确率不够再换yolov8s.ptdevice=cpu显式指定,避免有显卡但驱动不对时自动选 GPU 报错。projectname控制输出目录,跑完在corn_runs/exp1/weights/best.pt拿最优权重。训练过程中用tensorboard看 loss 曲线,如果box_loss震荡厉害,把学习率从默认 0.01 降到 0.001。

4. 黄曲霉素识别模型训练中的避坑与排查

4.1 现象:训练 loss 正常下降但 mAP 始终为 0

原因:标注文件里的class_iddata.yamlnames顺序不一致,或者标注 txt 里出现了class_id大于类别数的行。YOLOv8 不会报错,但会把所有预测当背景。

解决:用下面这段脚本检查所有 label 文件里的类别 id 分布:

from pathlib import Path from collections import Counter label_dir = Path('./dataset/train/labels') counter = Counter() for txt in label_dir.glob('*.txt'): with open(txt) as f: for line in f: if line.strip(): counter[int(line.split()[0])] += 1 print(counter)

如果输出里出现2或更大的 id,说明标注时类别映射错了,回去改class_map重新生成。

4.2 现象:验证准确率虚高到 99%,但实际推理一塌糊涂

原因:训练集和验证集里有同一张图片的不同增强版本,或者同一颗玉米的多个角度被分到了两个集合。数据泄露是准确率虚高的头号元凶。

解决:划分数据集时按“玉米粒个体”分组,同一颗玉米的所有图片必须进同一个子集。如果原始图片是按拍摄批次命名的,按批次前缀分组再随机划分。另外,验证集不要做任何增强,valaugment参数设False

4.3 现象:CPU 训练到一半被 kill,内存爆了

原因:batch设太大,或者workers默认 8 导致多进程读图占满内存。CPU 训练时workers设 2 就够,batch超过 16 在 16G 内存机器上很容易 OOM。

解决:在训练命令里加workers=2batch=4,并且用cache=False关闭缓存。如果还爆,把imgsz降到 416,准确率掉 1~2 个点但能跑完。

4.4 现象:霉变粒漏检严重,正常粒误检多

原因:正负样本极度不均衡,霉变粒实例太少。YOLOv8 默认的cls损失对少数类不友好。

解决:在data.yaml同级建一个hyp.yaml,调cls=1.5(默认 0.5),box=7.5保持,dfl=1.5。或者用copy_paste=0.3把霉变粒复制到正常图上,增加少数类实例。实测cls调到 1.5 后,霉变粒召回率能从 0.72 提到 0.89。

4.5 现象:推理时框的位置对,但类别全反了

原因:names里 0 和 1 的顺序和标注时相反。标注时霉变粒是 0,data.yaml里写成了0: normal_corn

解决:打开data.yamlclasses.txt逐行对照,确保0对应霉变粒。推理时用model.names打印一下映射关系,确认无误再部署。

5. 从 93.8% 准确率到产线落地:验证方法与调优技巧

5.1 用混淆矩阵和 PR 曲线定位 93.8% 背后的短板

93.8% 的验证准确率听起来不错,但要看是mAP50还是precision。如果是mAP50,说明模型在 IoU=0.5 时综合表现好;如果是precision,可能召回率很低。跑完训练后,YOLOv8 会在corn_runs/exp1/下生成confusion_matrix.pngPR_curve.png。重点看混淆矩阵里moldy_corn被预测成normal_corn的数量,这个数如果超过总霉变粒的 10%,说明模型对早期霉斑不敏感。

我一般会额外跑一次val并指定conf=0.3,因为默认conf=0.25会滤掉很多低置信度的霉变粒。命令:

yolo detect val \ model=corn_runs/exp1/weights/best.pt \ data=/home/user/corn_dataset/data.yaml \ conf=0.3 \ iou=0.5 \ device=cpu

参数说明:conf=0.3提高召回,iou=0.5是 NMS 的阈值,霉变粒密集时调到 0.4 避免框被合并。输出里看mAP50-95,如果这个值低于 0.6,说明框的定位精度不够,需要增加标注的精细度或换yolov8s

5.2 用 TensorBoard 看损失曲线,判断该不该继续训练

YOLOv8 训练时自动写 TensorBoard 日志,在corn_runs/exp1/下执行tensorboard --logdir .就能看。重点看三条线:train/box_losstrain/cls_lossval/cls_loss。如果train还在降但val已经平了甚至上升,就是过拟合,该早停。如果val/cls_loss一直震荡,把学习率降一半再跑 50 轮。

我习惯在patience=20的基础上,手动看val/cls_loss连续 10 轮不降就停,比等早停省时间。另外,lr/pg0曲线能看出学习率调度是否正常,如果一开始就掉到 0,说明warmup没生效,检查warmup_epochs是不是设成了 0。

5.3 模型导出与 CPU 推理速度优化

训练完的best.pt可以直接用,但 CPU 推理慢。导出 ONNX 能提速 20%~30%:

yolo export \ model=corn_runs/exp1/weights/best.pt \ format=onnx \ imgsz=640 \ simplify=True \ opset=12

逻辑说明:simplify=True会做图优化,opset=12兼容性好。导出后在 Python 里用onnxruntime推理,单张 640x640 图片在 i5 上大概 80~120ms。如果还要快,把imgsz降到 416,速度翻倍,准确率掉 1~2 个点。产线上如果要求实时,建议用yolov8n加 416 输入,配合conf=0.35平衡速度和召回。

5.4 一个具体技巧:用 TTA 把准确率再拉 1~2 个点

TTA(测试时增强)在推理时对图片做翻转、缩放,然后合并预测框。YOLOv8 的valpredict都支持augment=True

yolo detect predict \ model=corn_runs/exp1/weights/best.pt \ source=./test_images \ augment=True \ conf=0.3 \ save=True

注意 TTA 会让推理时间变成 3 倍左右,适合离线质检,不适合产线实时。实测在黄曲霉素数据集上,TTA 能把mAP50从 0.938 提到 0.951,但速度从 100ms 涨到 300ms。如果产线节拍允许,这个技巧值得加。

我自己的习惯是:先跑一版yolov8n加 640 输入拿到 baseline,再根据混淆矩阵决定是加数据、调损失权重还是换模型。不要一上来就上yolov8x,CPU 上跑不动,GPU 上也不一定比yolov8s好多少。黄曲霉素识别这种细粒度任务,标注质量比模型大小重要得多。希望帮到你。

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

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

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

立即咨询