简介:这份农作物多类别目标检测数据集面向农业AI开发者、农业院校研究者及智能农机视觉模块工程师,用于解决农田场景下作物种类识别与定位的样本匮乏问题。数据集覆盖香蕉、豆类、茄子、辣椒、黄瓜、大蒜、生姜、玉米、洋葱、豌豆、菠萝、马铃薯、水稻、高粱、番茄、小麦等16类主要农作物,涵盖谷物、蔬菜与经济作物三大类别,并特别包含豆类与豌豆、不同茄科作物等易混淆样本,便于训练高精度区分模型。资源包共2000个文件,以957张jpg图像与1041个txt标注文件为主,另含1个yaml配置文件与1份docx说明文档,压缩包约73.86MB,标注严格遵循YOLO格式,可直接用于YOLOv5/v7/v8等主流框架的迁移学习与微调。目前已有107人学习下载,适合快速搭建农田巡检、智能除草与自动化收割等视觉感知实验。
1. 从一次农田巡检 Demo 翻车说起:这套 16 类农作物检测数据集到底解决什么问题
去年帮一个做农业机器人的小团队看他们的巡检 Demo,模型在实验室里跑得挺欢,一到真实田块就抓瞎——番茄和辣椒的检测框互相串,豆类和豌豆几乎分不出来,洋葱和大蒜更是随机乱标。问题不在网络结构,也不在训练技巧,根子在数据:他们拿网上零散爬来的图片自己标,类别定义混乱、边界框松垮、遮挡样本几乎没有。这也是我后来一直建议做农业视觉项目的同学,先把数据集这件事定死的原因。
这份农作物多类别目标检测数据集,就是冲着这个痛点来的。它覆盖香蕉、豆类、茄子、辣椒、黄瓜、大蒜、生姜、玉米、洋葱、豌豆、菠萝、马铃薯、水稻、高粱、番茄、小麦共 16 类主要农作物,训练集 726 张、验证集 212 张、测试集 103 张,全部采用 YOLO 格式标注,标准化边界框坐标加类别标签,可以直接喂给 YOLOv5/v7/v8 乃至 yolov12 这类主流框架做迁移学习和微调。它适合三类人:正在做农业目标检测毕设或课设的学生、要搭农田巡检或智能除草视觉模块的开发者、以及需要标准化作物检测数据做交叉学科研究的实验室。下面我按需求、设计、落地、验收的顺序,把这份数据集怎么用、怎么避坑讲透。
2. 需求与技术选型:为什么是 YOLO 格式加 16 类划分
2.1 农业检测任务的真实约束
农田场景和通用 COCO 那类数据集完全不是一回事。第一,作物在田间是密集生长的,叶片互相遮挡、果实半露,边界框很容易画大或画小;第二,同一科属的作物外观高度相似,豆类和豌豆、茄子与辣椒在幼苗期几乎一个样,模型必须靠纹理和局部特征区分;第三,光照和背景变化剧烈,晴天正午和阴天傍晚的同一块地,颜色分布能差出一大截。这些约束决定了数据集不能只追求图片数量,类别定义的清晰度和标注的一致性才是命门。
这份数据集把 16 类拆成谷物(小麦、水稻、玉米、高粱)、蔬菜(番茄、黄瓜、洋葱、茄子、辣椒、大蒜、生姜、豆类、豌豆)、经济作物(香蕉、菠萝)三大块,还特意保留了易混淆作物的区分样本。这个划分方式是有讲究的:它没有按植物学分类硬切,而是按视觉可分性和应用场景来组织,方便你在训练时做类别分组消融实验。
2.2 为什么锁定 YOLO 标注格式
选 YOLO 格式不是跟风,是工程上的务实。YOLO 的标注是归一化的class_id x_center y_center width height,全部落在 0 到 1 之间,和图片分辨率解耦,换输入尺寸不用重标。相比之下 VOC 的 XML 是绝对像素坐标,COCO 的 JSON 结构又偏重,做实时检测时转换成本高。这份数据集直接给 YOLO 格式,意味着你可以跳过格式转换这一步,把精力放在模型和调参上。
下面是一个典型的 YOLO 标注文件长什么样,以及配套的data.yaml该怎么写:
# data.yaml —— 数据集配置文件,放在数据集根目录 path: ./crop_dataset # 数据集根路径 train: images/train # 训练集图片目录 val: images/val # 验证集图片目录 test: images/test # 测试集图片目录 # 类别数量与名称,顺序必须和标注文件里的 class_id 严格对应 nc: 16 names: 0: banana # 香蕉 1: bean # 豆类 2: eggplant # 茄子 3: chili # 辣椒 4: cucumber # 黄瓜 5: garlic # 大蒜 6: ginger # 生姜 7: corn # 玉米 8: onion # 洋葱 9: pea # 豌豆 10: pineapple # 菠萝 11: potato # 马铃薯 12: rice # 水稻 13: sorghum # 高粱 14: tomato # 番茄 15: wheat # 小麦nc必须等于 16,names的键值顺序就是标注里class_id的含义,一旦错位,模型会把番茄学成辣椒,而且 loss 曲线看起来还挺正常,这是最阴的坑。path建议用相对路径,方便整个数据集打包迁移。训练集、验证集、测试集按 726/212/103 的比例已经分好,不要自己再随机打乱重分,否则验证集和测试集的分布会漂移,评估结果不可信。
2.3 框架选型的取舍
摘要里提到可直接用于 YOLOv5/v7/v8,关键词里又带了 yolov12。我的建议是:如果你是要快速出结果交毕设,选 YOLOv8,生态成熟、文档全、训练脚本开箱即用;如果论文里想体现技术前沿性,可以拿 yolov12 做对比实验,但要注意新版本的依赖环境可能和你的显卡驱动打架,预留出折腾环境的时间。数据集本身是格式中立的,换框架只需要改data.yaml的路径,标注文件不用动,这也是选 YOLO 格式的另一个好处。
3. 总体设计:数据组织、类别体系与训练流程
3.1 目录结构与文件组织
拿到压缩包解压后,通常的目录组织是这样的,我一般会先花五分钟把结构理清楚再动手:
crop_dataset/ ├── data.yaml # 数据集配置 ├── images/ │ ├── train/ # 726 张训练图 │ ├── val/ # 212 张验证图 │ └── test/ # 103 张测试图 ├── labels/ │ ├── train/ # 与训练图同名的 .txt 标注 │ ├── val/ │ └── test/ └── crop_dataset.docx # 数据集说明文档图片和标注文件必须同名,只是扩展名不同。比如chilli_8_jpg.rf.71b9cb5407d240f706c0e72e817a39fb.jpg对应的标注就是chilli_8_jpg.rf.71b9cb5407d240f706c0e72e817a39fb.txt。文件名里那串rf.后面的哈希是标注工具自动生成的唯一标识,不要手动改,改了容易和标注对不上。crop_dataset.docx是说明文档,里面一般会写类别定义、采集场景和标注规范,训练前值得读一遍,尤其是类别边界模糊的地方,文档里通常有约定。
3.2 类别体系的视觉可分性设计
16 类里最容易翻车的是豆类和豌豆、茄子和辣椒这两组。数据集特意保留了这些易混淆样本,这是它的价值所在,但也意味着你在训练时要针对性处理。我的做法是:先跑一版基线,看混淆矩阵,如果豆类和豌豆的误判率高,就在数据增强里加更多的颜色抖动和随机裁剪,逼模型去看豆荚形状和颗粒排列这些细节特征,而不是靠整体色调蒙。
类别不平衡也要留意。16 类里香蕉、菠萝这类经济作物的样本量可能比水稻、小麦少,训练时可以用类别权重或者过采样来平衡。下面是一段检查各类别样本分布的脚本,训练前跑一遍心里有数:
import os from collections import Counter # 统计训练集标注里每个类别的框数量 label_dir = "crop_dataset/labels/train" class_names = ["banana","bean","eggplant","chili","cucumber","garlic", "ginger","corn","onion","pea","pineapple","potato", "rice","sorghum","tomato","wheat"] counter = Counter() for fname in os.listdir(label_dir): if not fname.endswith(".txt"): continue with open(os.path.join(label_dir, fname)) as f: for line in f: # YOLO 每行第一个数字是 class_id cls_id = int(line.split()[0]) counter[cls_id] += 1 # 打印每个类别的框数量,找出长尾类别 for i, name in enumerate(class_names): print(f"{name:10s}: {counter.get(i, 0)} boxes")这段脚本遍历训练集所有标注文件,统计每个class_id出现的次数。如果某个类别框数明显偏少(比如低于平均值的 30%),训练时就要给它加权,否则模型会偏向多数类,少数类召回率惨不忍睹。跑完这个统计,你对数据集的脾气就有底了。
3.3 训练流程与迁移学习策略
数据集规模是 726 张训练图,这个量级从头训不现实,必须用预训练权重做迁移学习。流程是:加载 COCO 预训练的 YOLO 权重,冻结主干网络先训几个 epoch 让检测头适应新类别,再解冻全网络微调。学习率用余弦退火,初始值设小一点,因为农业图像和 COCO 的自然图像分布差异大,学习率太猛会把预训练特征冲垮。
from ultralytics import YOLO # 加载预训练模型,用迁移学习而不是从头训 model = YOLO("yolov8n.pt") # 开始训练,参数按农业小数据集场景调 model.train( data="crop_dataset/data.yaml", epochs=100, # 小数据集容易过拟合,100 轮够用 imgsz=640, # 输入尺寸,和标注归一化基准无关 batch=16, # 显存不够就降到 8 lr0=0.001, # 初始学习率,迁移学习要小 patience=20, # 20 轮没提升就早停,省时间 augment=True, # 开启内置增强,缓解样本不足 project="crop_runs", # 训练结果保存目录 name="baseline" )epochs设 100 是因为 726 张图很容易过拟合,轮数太多验证 loss 会反弹。patience=20是早停,验证指标 20 轮不涨就停,避免无效训练。imgsz=640是 YOLO 的常用输入尺寸,和标注的归一化坐标无关,你可以改成 512 或 768 做对比。augment=True会启用 mosaic、翻转、色彩抖动等增强,对小数据集是刚需。训练完在crop_runs/baseline/weights/下会得到best.pt和last.pt,评估和推理都用best.pt。
4. 模块实现:从数据校验到推理部署的关键代码
4.1 数据完整性校验
训练前必须校验图片和标注是否一一对应,缺标注的图片会让训练直接报错,缺图片的标注则是脏数据。我一般会写个校验脚本先过一遍:
import os img_dir = "crop_dataset/images/train" lbl_dir = "crop_dataset/labels/train" # 收集图片和标注的文件名(不含扩展名) imgs = {os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.lower().endswith((".jpg", ".png", ".jpeg"))} lbls = {os.path.splitext(f)[0] for f in os.listdir(lbl_dir) if f.endswith(".txt")} # 找出只有图片没标注、或只有标注没图片的异常项 only_img = imgs - lbls only_lbl = lbls - imgs print(f"缺标注的图片: {len(only_img)} 张") print(f"缺图片的标注: {len(only_lbl)} 个") for name in list(only_img)[:5]: print(" 缺标注:", name)这个脚本用集合差集找出不匹配的项。正常情况两个数字都应该是 0。如果缺标注的图片不多,直接删掉;如果缺得多,说明数据集打包时出了问题,得回头找原始数据。这一步花两分钟,能省掉训练跑到一半崩掉的几小时。
4.2 标注质量抽检
YOLO 标注的常见问题是坐标越界(大于 1 或小于 0)和框过小。越界的框会让 loss 变成 NaN,框太小则是无效标注。抽检脚本如下:
import os lbl_dir = "crop_dataset/labels/train" bad_boxes = [] for fname in os.listdir(lbl_dir): if not fname.endswith(".txt"): continue with open(os.path.join(lbl_dir, fname)) as f: for lineno, line in enumerate(f, 1): parts = line.split() if len(parts) != 5: bad_boxes.append((fname, lineno, "字段数不对")) continue _, x, y, w, h = map(float, parts) # 检查坐标是否在 0-1 之间,宽高是否过小 if not all(0 <= v <= 1 for v in (x, y, w, h)): bad_boxes.append((fname, lineno, "坐标越界")) elif w < 0.01 or h < 0.01: bad_boxes.append((fname, lineno, "框过小")) print(f"可疑标注: {len(bad_boxes)} 处") for item in bad_boxes[:10]: print(item)坐标越界的框要手动修或删,框过小的(宽或高小于图宽高的 1%)基本是误标,也建议删。抽检完把有问题的标注文件列出来,逐个处理,别指望模型能容忍脏标注——它只会把错误学进去。
4.3 推理与可视化验证
训练完拿best.pt在测试集上跑推理,把检测结果画出来看,这是最直观的验收方式:
from ultralytics import YOLO model = YOLO("crop_runs/baseline/weights/best.pt") # 在测试集上推理,保存带框的可视化结果 results = model.predict( source="crop_dataset/images/test", conf=0.25, # 置信度阈值,低于此值的框不显示 iou=0.45, # NMS 的 IoU 阈值,控制重叠框合并 save=True, # 保存可视化图片 project="crop_runs", name="test_pred" ) # 打印每张图的检测类别和数量 for r in results: boxes = r.boxes names = [model.names[int(c)] for c in boxes.cls] print(r.path, "->", names)conf=0.25是常用起点,漏检多就降到 0.15,误检多就升到 0.4。iou=0.45控制非极大值抑制,密集生长的作物框重叠多,这个值可以适当调高到 0.5 减少误合并。跑完去crop_runs/test_pred/看可视化图,重点看易混淆类别有没有串、遮挡目标有没有漏。这一步的直观程度远超看指标数字,我每次都会亲自翻一遍测试集的预测图。
5. 避坑与常见问题排查
5.1 类别 ID 错位导致「学啥都像番茄」
现象:训练 loss 正常下降,但推理时所有作物都被标成同一类,混淆矩阵一片糊。原因:data.yaml里names的顺序和标注文件里class_id的实际含义对不上,模型学的是错位的映射。解决:打开几个标注文件,看class_id的分布,再对照crop_dataset.docx里的类别定义,确认names顺序。最稳妥的办法是拿一张已知类别的图推理,看输出的类别名对不对。
5.2 验证集指标虚高,测试集一塌糊涂
现象:验证集 mAP 冲到 0.9,测试集只有 0.5。原因:验证集和测试集分布不一致,或者训练时无意中把测试集图片混进了训练。解决:确认三个集合的图片没有重叠,检查文件名是否有重复。另外,如果验证集里某类样本特别多,指标会被拉高,要看每类的 AP 而不是只看总 mAP。
5.3 小目标漏检严重
现象:大棵的玉米、高粱检测得到,小颗的豌豆、豆类几乎全漏。原因:输入尺寸下采样后小目标特征丢失,或者标注里小目标的框本身就少。解决:提高输入尺寸到 768 或 1024,或者在模型里加 P2 小目标检测层。数据层面,检查小目标类别的框数量,必要时对小目标样本做复制增强。
5.4 过拟合:训练 loss 降到底,验证 loss 反弹
现象:训练到 60 轮后训练 loss 还在降,验证 loss 开始往上走,验证 mAP 停滞。原因:726 张图对 16 类任务来说偏少,模型记住了训练样本。解决:开强增强(mosaic、mixup、随机擦除),加 weight decay,用早停。如果还不行,考虑冻结更多层,只训检测头。
5.5 显存爆掉训练中断
现象:训练到一半报 CUDA out of memory。原因:batch设太大,或者imgsz太高。解决:把batch从 16 降到 8 或 4,imgsz从 640 降到 512。YOLO 支持梯度累积,batch=4配合accumulate=4等效于batch=16,显存不够时这是标准操作。
6. 验收与答辩:怎么证明这套数据集和模型真的能用
验收这件事,很多人栽在「只报一个 mAP」上。答辩老师或评审最想看的不是单一数字,而是你对数据、模型、场景三者关系的理解。我一般会准备三层证据。
第一层是定量指标。在测试集 103 张图上跑评估,输出每类的 Precision、Recall、mAP@0.5 和 mAP@0.5:0.95,做成表格。重点标出易混淆类别(豆类 vs 豌豆、茄子 vs 辣椒)的指标,如果这两组能到 0.7 以上,说明模型确实学到了细节特征,而不是靠颜色蒙。下面这段评估代码直接出每类指标:
from ultralytics import YOLO model = YOLO("crop_runs/baseline/weights/best.pt") # 在测试集上评估,输出每类指标 metrics = model.val( data="crop_dataset/data.yaml", split="test", # 指定用测试集,不是验证集 imgsz=640, conf=0.25 ) # 打印每类的 AP,定位弱项类别 for i, name in enumerate(model.names.values()): print(f"{name:10s} mAP50={metrics.box.ap50[i]:.3f}")split="test"是关键,很多人评估时忘了改,拿验证集数字当测试集报,一答辩就露馅。metrics.box.ap50是每类在 IoU=0.5 下的 AP,逐类打印出来,弱项一目了然。
第二层是定性可视化。挑 10 到 15 张有代表性的测试图,覆盖遮挡、密集、小目标、易混淆四种场景,把预测框和真值框并排画出来。答辩时放这张对比图,比任何数字都有说服力。如果某张图漏检了,别藏,主动分析原因——是目标太小还是被遮挡,然后给出改进方向,这反而显得你懂行。
第三层是场景适配说明。这份数据集的应用场景是农田巡检、智能除草、收割设备视觉模块,你要说清楚模型在这些场景下的边界:比如它适合白天光照均匀的条件,夜间红外图像没在训练集里,不能直接迁移。把适用边界讲明白,比吹嘘「通用」更让人信服。
| 验收项 | 合格线 | 检查方式 |
|---|---|---|
| 数据完整性 | 图片与标注一一对应 | 校验脚本输出 0 异常 |
| 标注质量 | 无越界、无过小框 | 抽检脚本输出 0 可疑 |
| 整体 mAP@0.5 | ≥ 0.75 | 测试集评估 |
| 易混淆类别 AP | ≥ 0.65 | 逐类指标表 |
| 可视化抽检 | 遮挡/密集场景无明显漏检 | 人工翻预测图 |
最后说个血泪经验:我早期做项目时,验收前一夜才发现测试集里混进了训练集的图,指标虚高得离谱,答辩现场被问「这张图你训练时见过吧」直接卡壳。从那以后我每次评估前都强制走一遍文件名去重和图片哈希比对,确认三个集合零重叠才敢报数字。这套流程看着笨,但能保命。希望这份数据集的用法和验收思路,能帮你把农业检测这个项目稳稳落地。
本文还有配套的精品资源,点击获取