简介这份玉米生长阶段目标检测数据集面向农业视觉算法开发者与目标检测学习者用于训练和验证玉米生育期识别模型。数据按幼苗、初期生长、快速生长、成熟前期、成熟期及成熟期不健康状态共6类划分覆盖从植株矮小到穗部发育、叶片老化的完整生长周期并包含病害或不健康样本适合YOLO系列模型训练与农业场景迁移实验。资源包共2000个文件以1482个txt标注文件、516张jpg图像为主另含1个yaml数据配置和1份docx说明文档压缩包约53.11MB其中训练集1035张、验证集294张、测试集153张标注采用YOLO边界框与类别标签格式可直接接入主流检测框架。目前已有461人学习下载适合需要快速构建农业目标检测基线、验证类别划分与数据增强策略的读者参考使用。1. 玉米生长阶段检测数据集从标注文件到YOLO训练我踩过的那些坑做农业视觉项目的兄弟大概率都遇到过这个场景模型在实验室里识别玉米叶片病害准得飞起一拉到田间地头就翻车——不是把拔节期认成苗期就是把抽雄期和成熟期搞混。问题往往不在网络结构而在数据集本身。我最近拆了一份玉米生长阶段检测数据集里面按苗期、拔节期、抽雄期、成熟期等关键生育期做了目标框标注格式是标准的目标检测标注结构可以直接喂给YOLO系列做训练。这份资源适合两类人一是做智慧农业、作物表型分析的算法工程师需要快速搭一个生长阶段识别的baseline二是农学背景想入门视觉检测的研究生拿它练手比用COCO强得多因为类别语义清晰、场景单一、标注密度适中。但别急着解压就开跑农业数据集有几个特有的坑比如光照跨度大、植株遮挡严重、标注粒度不统一这些在后面章节我会逐个拆开讲。2. 数据集结构拆解与YOLO格式转换别让标注格式成为第一道拦路虎2.1 先搞清楚手里的文件到底长什么样解压之后典型的结构一般是images/放原图labels/放同名txt标注外加一个classes.txt或data.yaml记录类别名。但农业数据集有个常见问题不同来源的包标注格式可能是Pascal VOC的XML、COCO的JSON也可能是已经转好的YOLO txt。你得先确认否则后面训练时loss不降你还以为是学习率的问题。我一般会先跑一段脚本做体检统计图片数量、标注文件数量、类别分布以及有没有空标注文件。空标注在农业数据集里特别常见——有些图片里玉米苗太小或者被杂草挡住标注员直接跳过了这种图如果留在训练集里会被YOLO当成背景负样本少量可以多了就会拉低召回。import os from collections import Counter img_dir images lbl_dir labels img_files [f for f in os.listdir(img_dir) if f.endswith((.jpg, .png, .jpeg))] lbl_files [f for f in os.listdir(lbl_dir) if f.endswith(.txt)] print(f图片数: {len(img_files)}, 标注数: {len(lbl_files)}) # 检查图片和标注是否一一对应 img_stems {os.path.splitext(f)[0] for f in img_files} lbl_stems {os.path.splitext(f)[0] for f in lbl_files} print(f有图无标注: {len(img_stems - lbl_stems)}) print(f有标注无图: {len(lbl_stems - img_stems)}) # 统计类别分布和空标注 cls_counter Counter() empty_count 0 for f in lbl_files: path os.path.join(lbl_dir, f) with open(path) as fh: lines [l.strip() for l in fh if l.strip()] if not lines: empty_count 1 continue for line in lines: cls_id line.split()[0] cls_counter[cls_id] 1 print(f空标注文件数: {empty_count}) print(f类别分布: {dict(cls_counter)})这段脚本的逻辑很直白先对齐图片和标注的文件名主干找出缺失对再逐行读标注统计每个类别的框数量和空文件数。参数上你只需要改img_dir和lbl_dir两个路径。重点看两个输出如果“有图无标注”数量超过总数的5%说明标注不完整训练时这些图会被当负样本如果某个类别框数极少比如成熟期只有几十个框那这个类别大概率训不出来需要考虑过采样或合并类别。2.2 从VOC/COCO转到YOLO txt的实操如果体检发现标注是XML或JSON就得转。VOC转YOLO的核心是把绝对坐标的xmin, ymin, xmax, ymax归一化成中心点加宽高的相对值。这里有个容易翻车的地方不同图片尺寸不一样归一化时必须用对应图片的宽高不能用统一值。import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_path, img_path, class_map): tree ET.parse(xml_path) root tree.getroot() w, h Image.open(img_path).size lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 归一化中心点和宽高 cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) return lines class_map {苗期: 0, 拔节期: 1, 抽雄期: 2, 成熟期: 3}class_map必须和你的data.yaml里names的顺序完全一致否则训练出来的类别全是错位的。归一化后的值必须在0到1之间如果出现大于1的说明原标注框超出了图片边界这种框要么裁掉要么修正直接留着会让YOLO的坐标回归震荡。2.3 data.yaml的写法与路径陷阱YOLOv5/v8都认data.yaml结构不复杂但路径写法坑了不少人。train和val最好用绝对路径或者相对于你执行训练命令时的当前目录。我见过有人写相对路径结果换台机器就找不到文件。path: /data/corn_growth train: images/train val: images/val nc: 4 names: [苗期, 拔节期, 抽雄期, 成熟期]nc是类别数必须和names长度一致。中文类别名在部分YOLO版本里会有编码问题如果训练时报UnicodeDecodeError把names改成英文或拼音然后在可视化阶段再映射回中文。另外path和train拼接后的路径必须真实存在YOLO不会帮你创建目录路径错了直接报FileNotFoundError别问我怎么知道的。3. 训练参数怎么设农业场景下的YOLO调参经验3.1 图像尺寸与增强策略的选择玉米生长阶段检测和通用目标检测最大的区别在于植株在图像中的尺度变化极大。苗期可能只占几十个像素抽雄期能占半张图。YOLO默认的imgsz640在苗期样本上会丢失细节我一般会拉到imgsz960甚至1280代价是显存占用翻倍batch size得降。数据增强方面农业场景要慎用Mosaic。Mosaic把四张图拼一起对通用检测提点明显但玉米不同生育期的颜色和形态差异大拼完之后模型容易学到“拼图边缘”这种伪特征。我的做法是前期用Mosaic快速收敛最后20个epoch关掉让模型在真实分布上微调。degrees旋转增强可以开因为田间拍摄角度本来就多变hsv_h色调增强要克制玉米从苗期到成熟期的颜色变化是重要特征过度色调扰动会让模型把拔节期和抽雄期搞混。yolo detect train \ data/data/corn_growth/data.yaml \ modelyolov8m.pt \ imgsz960 \ epochs150 \ batch8 \ mosaic1.0 \ close_mosaic20 \ degrees15.0 \ hsv_h0.01 \ hsv_s0.5 \ hsv_v0.3 \ lr00.01 \ patience30close_mosaic20表示最后20个epoch关闭Mosaic这个参数在YOLOv8里直接支持。patience30是早停耐心值验证集loss连续30轮不降就停避免过拟合。hsv_h0.01把色调扰动压到很低就是为了保住生育期的颜色特征。3.2 类别不平衡的处理农业数据集里各生育期的样本量往往不均匀。苗期和拔节期容易拍样本多抽雄期和成熟期植株高大、田间行走困难样本少。如果直接训模型会偏向多数类。除了过采样少数类还可以用YOLO的cls损失权重来调但更直接的办法是在数据集层面做平衡。我一般会统计每个类别的框数然后对少于阈值比如总框数的10%的类别在训练时复制其对应图片。注意是复制图片和标注不是复制框否则一张图里同一个目标出现多次NMS阶段会出问题。复制后重新生成train.txt索引文件即可。3.3 验证集划分的讲究随机划分验证集在农业数据上有个隐患同一块田、同一天的图片可能被分到训练和验证两边导致验证指标虚高。正确做法是按田块或按拍摄日期划分让验证集来自模型没见过的地块。如果你手里没有田块信息至少按图片的文件名前缀或时间戳做分组划分。import random from collections import defaultdict # 假设文件名格式为 fieldID_date_seq.jpg groups defaultdict(list) for f in img_files: field_id f.split(_)[0] groups[field_id].append(f) field_ids list(groups.keys()) random.shuffle(field_ids) split int(len(field_ids) * 0.8) train_fields set(field_ids[:split]) train_imgs [f for fid in train_fields for f in groups[fid]] val_imgs [f for fid in field_ids[split:] for f in groups[fid]]这样划分能保证同一块田的图片不会同时出现在训练和验证集里验证指标更接近真实部署效果。如果你的文件名没有田块信息那就用拍摄日期做分组逻辑一样。4. 避坑与排查农业数据集训练中最容易翻车的五个点4.1 现象训练loss正常下降但验证集mAP极低原因验证集和训练集来自同一块田或同一天数据泄漏导致训练指标虚高验证指标才是真实水平。另一种可能是验证集的标注格式和训练集不一致比如训练集是YOLO txt验证集还是VOC XMLYOLO读不到标注就当负样本。解决按田块或日期重新划分验证集确保分布独立。用前面2.1的体检脚本分别跑一遍训练集和验证集确认标注格式、类别ID、文件对应关系完全一致。4.2 现象模型把拔节期大量误判为苗期原因这两个生育期在视觉上确实接近尤其是拔节初期株高还没明显拉开。如果训练集里苗期样本远多于拔节期模型会倾向于把模糊样本判为苗期。解决先检查两个类别的样本量比例如果超过3:1对拔节期做过采样。然后在增强上给拔节期图片更多的尺度扰动让模型学到株高以外的特征比如叶片展开角度和茎秆粗细。还可以在损失函数里给拔节期更高的分类权重。4.3 现象推理时同一株玉米被检出多个框NMS后仍然重叠原因农业场景下植株密集YOLO的默认NMS IoU阈值是0.45对于重叠严重的玉米植株这个阈值会把不同植株的框互相抑制或者同一植株的多个预测框保留下来。解决把NMS IoU阈值调到0.5到0.6之间具体值在验证集上试。如果植株特别密集可以考虑用Soft-NMS替代标准NMS但YOLOv8默认不支持需要自己改后处理。更简单的办法是训练时用overlap_mask或者调整Anchor但YOLOv8是Anchor-free的所以重点还是调NMS阈值和置信度阈值。4.4 现象训练到一半突然报CUDA out of memory原因imgsz设太大加上batch没降或者Mosaic增强在后期还在跑拼图后的实际输入尺寸波动导致显存峰值超标。解决先把batch降到能跑的最小值然后开ampTrue混合精度训练能省30%左右显存。如果还不行把imgsz从960降到768或者用close_mosaic提前关掉Mosaic。另外注意workers设太大也会占显存一般设为CPU核数的70%就够了。4.5 现象中文类别名在可视化时显示为方框或乱码原因OpenCV的putText不支持中文YOLO自带的绘图函数用的就是OpenCV。解决可视化时用PIL的ImageDraw配合中文字体文件或者把类别名映射成英文再画。如果只是自己看映射成拼音最快。如果要出报告建议用PIL方案指定simhei.ttf或NotoSansCJK字体路径。5. 进阶技巧用TTA和类别映射把mAP再往上推一推训练完模型只是第一步推理阶段的技巧往往能再挤出几个点。我一般会在验证集上先跑一遍基础推理记录每个类别的AP然后针对低AP的类别做定向优化。测试时增强TTA是最容易上手的。YOLO官方支持augmentTrue推理时对图片做翻转、缩放等多尺度变换然后把结果融合。代价是推理速度慢3到4倍但mAP通常能涨1到3个点。对于玉米生长阶段这种类别间差异细粒度的任务TTA的收益比通用检测更明显。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict( sourceimages/val, imgsz960, conf0.25, iou0.5, augmentTrue, # 开启TTA saveTrue, save_txtTrue )augmentTrue就是TTA开关conf0.25是置信度阈值低于这个值的框直接丢弃。iou0.5是NMS阈值前面说过农业场景可以适当调高。跑完之后对比augmentFalse的结果如果某个类别的AP反而降了说明TTA对该类别的尺度变换不友好可以单独关掉。另一个技巧是类别映射。如果你的应用场景只关心“营养生长期”和“生殖生长期”两个大类可以把苗期和拔节期合并抽雄期和成熟期合并重新训练一个4类到2类的映射模型。类别少了类间混淆自然降低mAP会明显上升。但这是以牺牲细粒度信息为代价的看你的业务需求。还有一个我常用的验证方法把验证集按拍摄时间段分成上午、中午、下午三组分别跑推理看模型在不同光照下的表现差异。如果中午的AP明显低于早晚说明模型对强光过曝敏感训练时需要加更多的亮度扰动增强。这个分析比只看总体mAP有用得多能直接指导下一轮数据采集和增强策略。从那以后我每次拿到新的农业数据集都强制先跑一遍分组验证确认模型在真实田间条件下的表现而不是被随机划分的验证集给骗了。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?