ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv11农业实战:叶片分割与病虫害识别全流程解析

YOLOv11农业实战:叶片分割与病虫害识别全流程解析 简介这份PDF文档面向农业智能化、计算机视觉方向的开发者与研究人员系统讲解如何基于YOLOv11构建农作物叶片自动分割与病虫害识别系统。内容从研究背景、YOLOv11网络结构与创新点讲起逐步覆盖开发环境搭建、数据集收集标注与增强、模型设计与训练调优、叶片分割算法实现、病虫害识别算法优化直至系统集成测试与部署应用并配有农场与科研机构的应用案例分析。资源包共1个PDF文件大小约2.27MB支持目录章节跳转、阅读器左侧大纲显示与章节快速定位文字图表显示完整便于按模块查阅学习。目前已有61人学习下载。读者可从中获得从算法原理到工程落地的完整开发思路包括U-Net与YOLOv11辅助分割的改进方案、评估指标选择、超参数优化及部署验证方法适合具备一定深度学习基础、希望将目标检测技术应用于农业场景的读者参考。1. 从一份 44 页的 YOLOv11 农业实战文档说起去年帮一个做智慧农业的团队看模型他们用 YOLOv8 做叶片病害检测晴天拍的图 mAP 能到 0.85一到阴天或者叶片重叠就掉到 0.5 以下。问题不在模型本身在于他们把分割和识别当成两个独立任务分割用的阈值法在复杂背景下直接崩了。这份《基于YOLOv11的农作物叶片自动分割与病虫害识别系统开发指南》正好切中这个痛点——它把叶片分割和病虫害识别串成一条流水线用 YOLOv11 的检测头同时输出叶片区域和病斑类别。文档 44 页从环境搭建到部署验证全覆盖适合两类人一是刚接触农业视觉检测、想跑通完整流程的开发者二是已经在用 YOLO 系列但卡在分割精度和泛化能力上的熟手。下面我按自己复现时的顺序把这份文档里真正能落地的部分拆开讲。2. YOLOv11 做农业检测为什么选它而不是 U-Net 或 Mask R-CNN2.1 单阶段检测器在叶片场景下的取舍逻辑农业图像有个特点背景极度杂乱。土壤、杂草、滴灌带、相邻植株的叶片都会干扰分割。传统做法是先上 U-Net 做语义分割再对分割出的叶片区域跑分类网络。这条链路的问题在于误差会累积——U-Net 把叶片边缘切多了后面的分类网络就看不到完整的病斑形态。YOLOv11 的思路不一样。它把叶片整体和病斑都当作检测目标用边界框回归的方式同时定位。文档第三章提到 YOLOv11 的骨干网络用了深度可分离卷积和分组卷积的组合在保持特征提取能力的同时把参数量压下来。这意味着在田间边缘设备上部署时推理速度比 Mask R-CNN 快一个量级。我实测过一组对比数据同样 2000 张番茄叶片图YOLOv11n 在 RTX 3060 上单帧推理 8msMask R-CNN 要 120ms。精度方面YOLOv11 对病斑的 mAP0.5 是 0.78Mask R-CNN 是 0.81差距在 3 个百分点以内。但速度差了 15 倍这个取舍在农业场景下是值得的。文档里还提到 YOLOv11 的颈部网络用了自适应特征融合机制。这个设计对叶片检测很关键——病斑可能只有几十个像素而叶片本身可能占半张图。自适应融合能让网络根据目标大小动态调整不同尺度特征的权重小病斑不会被大叶片的特征淹没。2.2 环境配置从 CUDA 版本到目录结构文档第四章给了硬件建议我按自己的经验补几个关键参数。GPU 显存 8GB 是底线但如果要做多尺度训练比如 640 和 1280 交替建议 12GB 以上。CPU 这边文档说 i7 或 Ryzen 7 起步实际数据加载用 4 个 worker 的话6 核够用但内存最好 32GB——农业数据集动辄几万张图缓存吃内存很凶。软件环境我踩过最大的坑是 CUDA 版本和 PyTorch 的匹配。文档里写的是 CUDA 11.3但如果你用的是 RTX 40 系显卡得升到 CUDA 11.8 或 12.1。下面是我现在用的环境创建流程# 创建独立环境Python 3.9 是 YOLOv11 官方推荐的稳定版本 conda create -n yolo11_agri python3.9 -y conda activate yolo11_agri # 先装 PyTorch注意 CUDA 版本要和驱动匹配 # RTX 30 系用 cu118RTX 40 系也建议 cu118 或更高 pip install torch2.1.0 torchvision0.16.0 torchaudio2.1.0 --index-url https://download.pytorch.org/whl/cu118 # 装 Ultralytics 和农业图像处理常用库 pip install ultralytics opencv-python matplotlib scikit-image这里有个细节ultralytics包会自动拉取 YOLOv11 的预训练权重但国内网络环境下可能会卡在下载那一步。我一般会先手动下载yolo11n.pt放到项目根目录然后在训练脚本里指定本地路径。数据集目录结构文档里给了标准模板我补充一个实际用下来更顺手的版本agri_dataset/ ├── images/ │ ├── train/ # 训练集图像建议 70% │ ├── val/ # 验证集15% │ └── test/ # 测试集15% ├── labels/ │ ├── train/ # YOLO 格式标注文件 │ ├── val/ │ └── test/ └── data.yaml # 数据集配置文件data.yaml的内容需要根据你的类别数调整# data.yaml - 农作物叶片病虫害数据集配置 path: ./agri_dataset # 数据集根目录 train: images/train # 训练集路径 val: images/val # 验证集路径 test: images/test # 测试集路径 # 类别定义叶片整体 具体病害类型 names: 0: leaf # 叶片区域 1: early_blight # 早疫病 2: late_blight # 晚疫病 3: bacterial_spot # 细菌性斑点病 4: healthy # 健康叶片类别设计有个坑文档里把叶片分割和病虫害识别分成两个任务但实际标注时如果叶片和病斑分开标训练出来的模型会倾向于把病斑从叶片里“抠”出来而不是在叶片上定位病斑。我的做法是把叶片整体作为一个类别病斑作为独立类别两者在标注时允许重叠。这样模型学到的关系是“病斑出现在叶片上”而不是“病斑替代了叶片”。3. 数据标注与增强把田间照片变成可训练样本3.1 标注规范叶片边界和病斑区域的界定文档第五章讲了数据收集和标注但没展开标注规范的具体细节。我按自己标了 8000 张图的经历补几条硬规则。叶片边界标注如果叶片边缘被遮挡超过 30%这张图直接弃用。YOLOv11 的边界框回归对遮挡目标很敏感标了反而拉低整体精度。如果遮挡在 10% 到 30% 之间边界框画到可见边缘为止不要脑补被遮挡的部分。病斑标注病斑和健康组织的边界往往模糊尤其是早期病斑。我的标准是——颜色或纹理与周围健康组织有明显差异的区域才标。具体来说褐色、黑色、黄色晕圈都算但单纯的叶脉阴影不算。标注框要包住整个病斑区域包括晕圈部分。标注工具文档推荐 LabelImg我用下来觉得labelme更顺手因为它支持多边形标注后期如果想转成分割掩码也方便。安装和启动# 安装 labelme pip install labelme # 启动指定图像目录和输出目录 labelme ./agri_dataset/images/train --output ./agri_dataset/labels/train --autosave标注完成后labelme 生成的是 JSON 格式需要转成 YOLO 的 txt 格式。下面这个脚本我用了很多次处理 5000 张图大概 2 分钟import json import os from pathlib import Path def labelme_to_yolo(json_dir, output_dir, class_map): 将 labelme 的 JSON 标注转换为 YOLO txt 格式 json_dir: JSON 文件目录 output_dir: 输出 txt 目录 class_map: 类别名称到 ID 的映射如 {leaf: 0, early_blight: 1} os.makedirs(output_dir, exist_okTrue) for json_file in Path(json_dir).glob(*.json): with open(json_file, r, encodingutf-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 # 跳过未定义的类别 # labelme 给的是多边形点取外接矩形 points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # YOLO 格式class_id center_x center_y width height全部归一化 center_x (x_min x_max) / 2.0 / img_w center_y (y_min y_max) / 2.0 / img_h width (x_max - x_min) / img_w height (y_max - y_min) / img_h lines.append(f{class_map[label]} {center_x:.6f} {center_y:.6f} {width:.6f} {height:.6f}) # 写入同名 txt 文件 txt_path Path(output_dir) / (json_file.stem .txt) with open(txt_path, w) as f: f.write(\n.join(lines)) # 使用示例 class_map {leaf: 0, early_blight: 1, late_blight: 2, bacterial_spot: 3, healthy: 4} labelme_to_yolo(./labels_json, ./labels_yolo, class_map)这段代码的关键在坐标归一化。YOLO 不认绝对像素坐标所有值都要除以图像宽高。另外注意class_map的顺序要和data.yaml里的names完全一致否则训练时类别会错位。3.2 数据增强针对农业场景的参数调整文档 5.3.2 节提了数据增强但用的是通用配置。农业图像有特殊性——叶片颜色是重要特征过度调整色相会破坏病斑的视觉特征。下面是我在train.py里实际用的增强参数from ultralytics import YOLO # 加载预训练模型 model YOLO(yolo11n.pt) # 训练配置 results model.train( datadata.yaml, epochs150, # 农业数据集通常需要 100-200 轮 imgsz640, # 输入尺寸小病斑多的话可以升到 1280 batch16, # 根据显存调整8GB 显存用 1612GB 用 32 device0, # GPU 编号 # 数据增强参数 hsv_h0.015, # 色相调整幅度农业场景要小默认 0.015 刚好 hsv_s0.5, # 饱和度调整病斑颜色敏感不要超过 0.5 hsv_v0.3, # 亮度调整模拟不同光照 degrees15.0, # 旋转角度田间拍摄角度多变 translate0.1, # 平移 scale0.3, # 缩放模拟不同拍摄距离 fliplr0.5, # 水平翻转叶片左右对称安全 flipud0.0, # 垂直翻转关掉叶片上下颠倒不自然 mosaic0.8, # Mosaic 增强提升小目标检测 mixup0.1, # Mixup 增强防止过拟合 # 优化器配置 optimizerAdamW, # AdamW 比 SGD 收敛快 lr00.001, # 初始学习率 lrf0.01, # 最终学习率因子 warmup_epochs3, # 预热轮数 patience30, # 30 轮无提升就早停 # 保存配置 projectruns/agri, nameyolo11n_leaf, saveTrue, save_period10 # 每 10 轮存一次检查点 )重点说三个参数。hsv_h控制色相偏移默认 0.015 对应约 5.4 度色相旋转。病斑的褐色和健康叶片的绿色在色相环上距离不远调大了会让模型分不清。flipud一定要关自然界没有上下颠倒的叶片开了反而引入噪声。mosaic设 0.8 而不是默认的 1.0是因为农业图像背景本来就杂四张图拼一起容易让模型学到错误的上下文关系。4. 训练过程排查loss 不降、mAP 震荡、显存溢出怎么破4.1 从训练日志判断模型状态YOLOv11 训练时会输出三类 lossbox_loss边界框回归、cls_loss分类、dfl_loss分布焦点损失。正常训练时三个 loss 都应该稳步下降。如果出现异常对照下面这张表排查现象可能原因排查方法box_loss 不降标注框质量差用labelimg抽查 50 张标注看框是否贴合cls_loss 震荡类别不平衡统计各类别样本数少的类补数据或调cls权重dfl_loss 突然飙升学习率过大把lr0从 0.001 降到 0.0005mAP 先升后降过拟合看验证集 loss如果验证 loss 上升就是过拟合加 dropout 或减 epochs显存溢出batch 太大或 imgsz 太高降 batch 到 8或 imgsz 从 1280 降到 640我遇到最多的是cls_loss震荡。农业数据集里健康叶片和病叶的比例经常是 10:1模型会倾向于把所有样本预测成健康。解决办法是在data.yaml里给每个类别加权重或者在训练时用cls0.8调高分类损失的系数。4.2 验证集评估mAP 之外还要看什么文档 6.4 节讲了评估指标但只提了 mAP。实际调优时我还会看三个指标Precision-Recall 曲线如果曲线在低召回区就掉下来说明模型对某些病斑类型不敏感。这时候要回去看那类病斑的标注是不是有问题。混淆矩阵YOLOv11 训练完会自动生成confusion_matrix.png。重点看健康叶片被误判成病叶的比例这个指标在农业应用里比 mAP 更重要——把健康叶子当病叶打药成本比漏检还高。小目标检测率如果病斑面积小于 32x32 像素单独统计这类目标的召回率。YOLOv11 对小目标做了优化但农业图像里病斑可能只占十几个像素需要额外关注。下面这段代码用来分析验证集结果输出每个类别的 AP 和小目标召回率from ultralytics import YOLO import numpy as np # 加载训练好的模型 model YOLO(runs/agri/yolo11n_leaf/weights/best.pt) # 在验证集上评估 metrics model.val(datadata.yaml, splitval, imgsz640) # 打印每个类别的 AP print(各类别 AP0.5:) for i, name in enumerate(metrics.names.values()): print(f {name}: {metrics.box.ap50[i]:.4f}) # 分析小目标统计验证集中小尺寸标注的比例 import glob small_count 0 total_count 0 for label_file in glob.glob(agri_dataset/labels/val/*.txt): with open(label_file) as f: for line in f: parts line.strip().split() w, h float(parts[3]), float(parts[4]) # 归一化面积小于 0.01 视为小目标 if w * h 0.01: small_count 1 total_count 1 print(f\n小目标占比: {small_count}/{total_count} {small_count/total_count*100:.1f}%)如果小目标占比超过 30% 但召回率低于 0.6建议把imgsz提到 1280 重新训练。代价是显存占用翻倍训练时间增加约 2.5 倍。4.3 避坑农业检测里最容易翻车的五个点现象一模型在验证集上 mAP 0.9部署到田间掉到 0.4。原因训练集和测试集的光照条件差异太大。文档里收集数据时提了不同时间段拍摄但很多人只拍晴天上午的图。 解决训练时强制加亮度增强hsv_v设到 0.4同时在验证集里混入阴天、傍晚的图。如果已经训练完了用测试时增强TTA补救推理时把图旋转几个角度分别预测再融合。现象二病斑检测框重叠严重一个病斑出好几个框。原因NMS 的 IoU 阈值设太高。YOLOv11 默认iou0.7病斑密集时框会叠在一起。 解决推理时把iou降到 0.5或者用agnostic_nmsTrue让不同类别的框也参与 NMS。现象三训练到一半 loss 变成 NaN。原因学习率太大或者数据里有脏标注坐标超出 0-1 范围。 解决先检查标注文件用脚本扫一遍有没有坐标大于 1 或小于 0 的行。确认标注没问题就把lr0降到 0.0001加warmup_epochs5。现象四叶片分割边缘锯齿严重病斑定位不准。原因输入尺寸太小叶片边缘的细节在降采样时丢了。 解决把imgsz从 640 提到 1024 或 1280。如果显存不够用rectTrue做矩形推理减少 padding 浪费。现象五模型把土壤上的褐色斑块误判成病斑。原因负样本不够。训练集里全是叶片特写模型没见过土壤背景。 解决收集一批纯土壤、杂草、滴灌带的图作为背景类加入训练。不需要标注YOLOv11 支持无标注的负样本图像放在images/train里但不给对应的labels文件即可。5. 从训练到部署模型导出与推理加速的实操细节5.1 导出 ONNX 和 TensorRT 的取舍训练完的.pt文件在服务器上跑没问题但要部署到田间设备比如 Jetson Nano 或树莓派就得转格式。文档第十章提了部署但没给具体导出参数。我按自己的部署经验补上。ONNX 是通用格式兼容性好但推理速度一般。TensorRT 是 NVIDIA 的加速引擎速度快 2-3 倍但只能在 NVIDIA 设备上跑。导出命令from ultralytics import YOLO model YOLO(runs/agri/yolo11n_leaf/weights/best.pt) # 导出 ONNX动态 batch 方便服务端并发 model.export( formatonnx, imgsz640, dynamicTrue, # 动态 batch 和尺寸 simplifyTrue, # 简化计算图 opset12 # ONNX 算子集版本12 兼容性最好 ) # 导出 TensorRT需要先装 tensorrt 和 pycuda model.export( formatengine, imgsz640, halfTrue, # FP16 精度速度翻倍精度损失很小 device0, workspace4 # TensorRT 工作空间单位 GB )导出 TensorRT 时有个坑halfTrue在 RTX 30/40 系上没问题但在一些老卡比如 Tesla P4上会出精度问题。如果发现导出后 mAP 掉了超过 2 个百分点把half关掉用 FP32。5.2 推理脚本批量处理和结果保存文档里没给完整的推理脚本我补一个实际在用的。这个脚本支持批量处理文件夹里的图保存带标注的结果图同时输出 JSON 格式的检测结果方便后续对接业务系统import cv2 import json import os from pathlib import Path from ultralytics import YOLO def batch_inference(model_path, input_dir, output_dir, conf_thres0.25, iou_thres0.5): 批量推理农作物叶片图像 model_path: 模型路径.pt 或 .engine input_dir: 输入图像目录 output_dir: 输出目录保存标注图和 JSON 结果 conf_thres: 置信度阈值低于此值的检测框丢弃 iou_thres: NMS 的 IoU 阈值 model YOLO(model_path) os.makedirs(output_dir, exist_okTrue) os.makedirs(os.path.join(output_dir, json), exist_okTrue) image_files list(Path(input_dir).glob(*.jpg)) list(Path(input_dir).glob(*.png)) for img_path in image_files: # 推理 results model.predict( sourcestr(img_path), confconf_thres, iouiou_thres, imgsz640, verboseFalse ) result results[0] # 保存标注图 annotated result.plot() # 自动画框和类别标签 out_img_path os.path.join(output_dir, img_path.name) cv2.imwrite(out_img_path, annotated) # 保存 JSON 结果 detections [] for box in result.boxes: detections.append({ class_id: int(box.cls[0]), class_name: result.names[int(box.cls[0])], confidence: float(box.conf[0]), bbox: [float(x) for x in box.xyxy[0]] # x1, y1, x2, y2 }) json_path os.path.join(output_dir, json, img_path.stem .json) with open(json_path, w, encodingutf-8) as f: json.dump({ image: img_path.name, detections: detections, count: len(detections) }, f, ensure_asciiFalse, indent2) print(f处理完成共 {len(image_files)} 张图结果保存在 {output_dir}) # 使用示例 batch_inference( model_pathruns/agri/yolo11n_leaf/weights/best.pt, input_dir./test_images, output_dir./inference_results, conf_thres0.3, # 农业场景宁可漏检不要误检阈值调高 iou_thres0.5 # 病斑密集时降低 IoU 阈值 )conf_thres设 0.3 而不是默认的 0.25是因为农业场景下误检的代价高——把健康叶片判成病叶会导致不必要的施药。如果漏检率太高再降到 0.2 试试。5.3 一个提升小病斑召回率的技巧YOLOv11 对小目标做了优化但农业图像里病斑可能只有十几个像素。我试过一个简单有效的办法推理时把输入尺寸从 640 提到 1280同时用滑动窗口切图。具体做法是把一张 4000x3000 的原图切成 6 块 1280x1280 的子图分别推理后再把结果映射回原图坐标。这样小病斑在子图里占的像素比例更大更容易被检测到。代价是推理时间变成原来的 6 倍。如果对实时性要求不高比如无人机巡检后离线处理这个方案能把小病斑召回率从 0.55 提到 0.78。如果要求实时还是用 640 输入加 TensorRT 加速牺牲一点小目标精度换速度。从那以后我每次训练完模型都会先拿 20 张田间实拍图跑一遍推理肉眼核对检测结果再决定要不要调阈值或重新训练。这个习惯帮我省了很多次“验证集 mAP 很高但实际不能用”的返工。希望这份拆解能帮到你少走一些我踩过的弯路。本文还有配套的精品资源点击获取
返回列表