简介:这份植物营养健康检测数据集面向农业AI开发者、智慧农业应用团队及农业院校师生,用于构建可自动识别植物营养缺乏区域并分类的实例分割模型,辅助精准施肥与作物健康监测。数据覆盖healthy、iron、magnesium、nitrogen、phosphorus、potassium六类状态,训练集1362张、验证集129张、测试集65张,标注采用YOLO格式并含实例分割信息,可直接加载至主流深度学习框架,兼顾检测与分割任务。压缩包共2000个文件,以1556个txt标注、442张jpg图像为主,另含1个yaml配置与1份docx说明,整体约69.52MB,目录结构清晰便于按类别检索。目前已有77人学习下载。读者可据此快速搭建植物营养诊断基线模型,开展多类别检测与分割实验,并扩展至分类任务,为精准农业研究与教学提供可靠数据支撑。
1. 植物营养健康检测数据集:从叶片到果实的多类别标注实战
拿到一个植物营养健康检测数据集,第一反应不该是“有多少张图”,而是“标注粒度能不能撑起我的业务”。这个包里的数据覆盖了叶片、果实、整株三个层级,标签体系同时包含目标检测框和实例分割掩码,类别上区分了缺氮、缺磷、缺钾、缺铁、缺镁、健康以及病害侵染等状态。换句话说,它不是一个单纯的“植物病害分类”数据集,而是把营养胁迫和病理表现放在同一套标注规范里。对于做智慧农业、温室巡检、无人机巡田的团队来说,这种多类别、多任务的数据结构,直接决定了你后面是训一个检测器还是分割器,或者干脆走 YOLOv8-seg 的多任务路线。适合谁?适合已经跑通过 COCO 或 YOLO 格式、想往农业垂直场景迁移的算法工程师,也适合需要快速验证“营养诊断”产品原型的团队。不适合只想拿现成权重做 demo 的人,因为这份数据的价值在标注结构和类别定义,不在预训练模型本身。
2. 拆包先看标注格式:YOLO txt 与 COCO json 的取舍
2.1 目录结构与标注文件对应关系
解压后常见结构是 images 和 labels 平行目录,labels 下分 train/val/test,每个 txt 对应一张图。但这份数据因为涉及实例分割,txt 里每行不是 5 列而是多边形点列:class_id x1 y1 x2 y2 ... xn yn,坐标是归一化后的。如果你拿到的是 COCO json,那 instances 里会有 segmentation 字段,bbox 和 area 也齐全。先别急着转格式,用几行 Python 把类别分布和标注数量摸清楚,这一步能帮你判断要不要做类别合并。
import os from collections import Counter label_dir = "labels/train" class_counter = Counter() instance_counter = 0 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: parts = line.strip().split() if len(parts) < 5: continue cls_id = int(parts[0]) class_counter[cls_id] += 1 instance_counter += 1 print("类别分布:", class_counter) print("实例总数:", instance_counter)这段代码只做一件事:统计每个类别的实例数。参数上注意len(parts) < 5这个判断,因为分割标注的点数必须是偶数且至少两个点,少于 5 列说明这行有问题,直接跳过比报错好。跑完你会看到某些类别可能只有几十个实例,这时候就要决定是合并到相近类别还是做过采样。常见做法是先把缺素类合并成“营养胁迫”一个大类,病害单独保留,健康类作为负样本平衡。
2.2 检测框与分割掩码的转换逻辑
如果你只想做目标检测,不需要多边形,那就把点列转成外接矩形。注意 YOLO 格式的 bbox 是中心点加宽高,且归一化。转换时别用min/max直接算完就完事,要检查宽高是否大于 0,否则会出现零面积框导致训练时 loss 为 nan。
def polygon_to_bbox(points): xs = points[0::2] ys = points[1::2] x_min, x_max = min(xs), max(xs) y_min, y_max = min(ys), max(ys) cx = (x_min + x_max) / 2 cy = (y_min + y_max) / 2 w = x_max - x_min h = y_max - y_min if w <= 0 or h <= 0: return None return cx, cy, w, h逻辑说明:输入是归一化后的点列,输出是 YOLO 检测格式的四个值。参数上w <= 0 or h <= 0是血泪经验,有些标注员在叶片边缘画点时会重复同一个坐标,导致宽高为零。遇到这种直接丢弃,不要试图修复,修复成本比重新标还高。反过来,如果你要做实例分割,就保留原始点列,但要注意 YOLOv8-seg 要求每个实例的点数一致或者用 padding,常见做法是统一采样到 32 个点,用cv2.approxPolyDP做轮廓近似。
3. 训练配置怎么定:YOLOv8-seg 的多类别参数与数据增强
3.1 data.yaml 的类别映射与路径陷阱
YOLOv8 的 data.yaml 看着简单,但农业数据集最容易翻车的地方就在路径和类别名。path建议写绝对路径,train和val写相对路径,否则在不同机器上跑会找不到文件。类别名不要用中文,也不要用空格,用下划线连接,比如nitrogen_deficiency、healthy。names 的顺序必须和标注里的 class_id 严格对应,错一位整个训练就废了。
path: /data/plant_nutrient train: images/train val: images/val test: images/test names: 0: healthy 1: nitrogen_deficiency 2: phosphorus_deficiency 3: potassium_deficiency 4: iron_deficiency 5: magnesium_deficiency 6: disease_spot 7: pest_damage参数说明:path是数据集根目录,train/val/test是相对路径。names 里我一般会把健康类放在 0,因为很多评估脚本默认 0 是背景或正常类,这样混淆矩阵看起来更直观。注意如果你的标注里缺素类别有重叠,比如一片叶子同时缺氮和缺镁,那要么改成多标签,要么在标注阶段就选主导症状。YOLO 不支持一个实例多个类别,这是硬边界。
3.2 针对叶片纹理的增强策略
植物叶片数据有个特点:颜色是核心特征,但光照变化极大。如果你直接上 HSV 增强,饱和度一拉,缺氮的黄化和病害的黄斑就混了。我一般会关掉hsv_h和hsv_s,只保留hsv_v做亮度扰动,范围控制在 0.2 以内。另外mosaic增强对农业场景很有效,因为叶片在自然环境下本来就是重叠的,mosaic 能模拟这种遮挡。但mixup要慎用,它会把两片叶子的纹理叠在一起,缺素症状直接糊掉。
from ultralytics import YOLO model = YOLO("yolov8s-seg.pt") results = model.train( data="data.yaml", epochs=120, imgsz=640, batch=16, hsv_h=0.0, hsv_s=0.0, hsv_v=0.2, mosaic=1.0, mixup=0.0, copy_paste=0.1, degrees=15.0, translate=0.1, scale=0.3, fliplr=0.5, flipud=0.0, patience=30, device=0 )逻辑说明:hsv_h=0.0和hsv_s=0.0是为了保住颜色特征,hsv_v=0.2模拟阴天和晴天的亮度差。copy_paste=0.1是分割任务里比较有用的增强,把实例抠出来贴到其他图上,能增加小目标样本。flipud=0.0是因为植物叶片上下翻转不符合自然生长规律,除非你的数据是俯拍且无方向性。patience=30是早停,农业数据集标注噪声大,训太久容易过拟合到错误标注上。跑完看results.png里的 mask mAP50 和 box mAP50,如果两者差距超过 10 个点,说明分割掩码质量有问题,回去检查多边形标注。
4. 避坑与排查:标注噪声、类别不平衡与显存爆炸
4.1 现象:训练 loss 震荡不收敛,mAP 卡在 0.3 以下
原因:标注里存在大量零面积框或重复标注。农业数据集的标注员经常在叶片边缘反复描点,导致同一个实例出现多个几乎重合的框。YOLO 的 NMS 会把这些框当成不同目标,loss 自然下不去。
解决:训练前跑一遍清洗脚本,对每个实例计算 IoU,超过 0.85 的只保留面积最大的那个。另外检查labels里有没有空文件,空文件对应的图片要么删掉,要么放到背景类里。
4.2 现象:某些类别 mAP 始终为 0
原因:类别实例数太少,或者类别名在 data.yaml 里写错。常见的是nitrogen_deficiency写成了nitrogen_deficency,训练时不会报错,但评估时按名字匹配就找不到。
解决:用model.val()后打印confusion_matrix.png,看哪一列全是 0。如果是实例数少于 50,考虑合并到相近类别,或者用copy_paste增强专门给小类做过采样。
4.3 现象:训练到一半 CUDA out of memory
原因:imgsz设太大,或者batch设太高。分割任务比检测任务多一个 mask 分支,显存占用大概是检测的 1.5 倍。另外copy_paste增强会在训练时动态生成新图,显存峰值比静态图高。
解决:先把imgsz从 640 降到 512,如果还爆就降batch到 8。或者用amp=True混合精度,但注意农业数据里颜色特征敏感,amp 有时会让颜色通道的梯度不稳定,建议先试amp=False跑几个 epoch 看 loss 曲线。
4.4 现象:验证集 mAP 很高,但实际推理时漏检严重
原因:验证集和训练集来自同一批图片的随机划分,叶片背景、光照、拍摄角度高度相似。模型学到了背景捷径,而不是真正的营养症状特征。
解决:按拍摄批次或地块划分 train/val,不要随机分。如果数据里没有批次信息,至少按图片的亮度均值做分层抽样,保证验证集的光照分布和训练集有差异。这一步做完,mAP 通常会掉 5 到 10 个点,但掉下来的才是真实水平。
4.5 现象:分割掩码边缘锯齿严重,小叶片几乎变成多边形
原因:标注时点太少,或者cv2.approxPolyDP的 epsilon 设太大。YOLOv8-seg 输出的掩码分辨率是 160x160,如果原图里叶片只占 20x20 像素,上采样后边缘必然粗糙。
解决:训练时把imgsz提到 1024,或者用retina_masks=True让掩码在原图分辨率上生成。但注意这会把显存占用再拉高一个档次,量力而行。另一个办法是在推理后处理里用cv2.GaussianBlur对掩码做一次平滑,再二值化,边缘会自然很多。
5. 从训练到落地:用 ONNX 导出与 TensorRT 加速的实操细节
训练完的.pt文件直接拿去部署,在服务器上跑还行,到了边缘设备比如 Jetson 或 RK3588 就吃力了。我一般会先导出 ONNX,再转 TensorRT,中间有两个参数必须手动改。第一个是opset,YOLOv8-seg 建议用 12,低于 11 不支持某些分割算子。第二个是simplify,打开后 ONNX 会做常量折叠,但有时会把 mask 分支的 reshape 折叠错,导致输出维度对不上。所以导出后一定要用onnxruntime跑一张测试图,和 PyTorch 的输出做余弦相似度对比,低于 0.99 就关掉 simplify 重新导。
from ultralytics import YOLO model = YOLO("runs/segment/train/weights/best.pt") model.export( format="onnx", opset=12, simplify=False, dynamic=False, imgsz=640 )逻辑说明:simplify=False是保险做法,虽然模型大一点,但输出稳定。dynamic=False固定输入尺寸,TensorRT 构建引擎时更快。导出后你会得到best.onnx,用trtexec转 engine 时加上--fp16,速度能再提一截。但注意 fp16 对颜色敏感,如果发现缺素类别的置信度整体下降,就换回 fp32。
trtexec --onnx=best.onnx --saveEngine=best.engine --fp16 --workspace=4096参数说明:--workspace=4096是 4GB 显存工作区,分割模型建议不低于这个值。--fp16开启半精度,如果精度掉得厉害就去掉。转完 engine 后,用polygraphy或者自己写个脚本对比 ONNX 和 engine 的输出,重点看 mask 分支的 IoU 差异,超过 0.02 就说明精度损失不可接受。
最后说一个我自己的习惯:每次拿到新的农业数据集,不管标注看起来多干净,我都会先抽 20 张图用labelme或cv2可视化一遍,把框和掩码叠在原图上。这一步花不了半小时,但能提前发现 80% 的标注问题。从那以后我每次训新数据前都强制走一遍可视化,再也没出现过训到一半发现类别标反的翻车事故。希望帮到你。
本文还有配套的精品资源,点击获取