ARTICLE DETAIL

资讯详情

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

YOLOv11实战:农作物叶片分割与病虫害识别系统搭建

YOLOv11实战:农作物叶片分割与病虫害识别系统搭建 简介这份PDF文档面向农业智能化、计算机视觉方向的开发者与研究人员系统讲解如何基于YOLOv11构建农作物叶片自动分割与病虫害识别系统。内容从研究背景与YOLO系列演进讲起逐步深入到网络结构、开发环境搭建、数据集采集标注与增强、模型设计与训练调优并分别展开传统图像处理与深度学习两条分割算法路线以及病虫害识别算法的多层面优化策略最后覆盖系统集成、测试、部署与农业应用案例分析。资源包共1个PDF文件约2.27MB支持目录章节跳转与阅读器左侧大纲快速定位44页内容完整、图表清晰便于按模块查阅。目前已有61人学习。读者可借此掌握从数据准备到模型落地部署的完整开发链路理解YOLOv11在农业场景中的调优思路与工程实践方法适合作为课程设计、科研项目或农业智能检测系统开发的学习参考。1. 从一张发黄的玉米叶说起YOLOv11 到底能不能同时干分割和识别去年夏天一个做种植合作社的朋友发来一张玉米叶照片叶片边缘已经出现典型的褪绿条纹他问我能不能写个东西手机拍一张就告诉他这是什么病、病斑占了多大面积。这个需求听起来简单落到工程上其实是两个任务叠在一起像素级分割出病斑区域再对整片叶子的病害类别做识别。传统做法是先用一个分割网络比如 U-Net抠出病斑再训一个分类网络判断类别两套权重、两次推理部署到边缘设备上延迟直接翻倍。YOLOv11 的出现让这件事有了另一种解法。Ultralytics 在 2024 年发布的这个版本把分割segmentation、检测detection、姿态pose、分类classify统一到同一套训练框架里yolo11n-seg.pt这类权重既能输出实例掩码又能给出类别和置信度。对农作物叶片场景来说这意味着一次前向推理就能同时拿到「病斑在哪、有多大、是什么病」三样信息。这篇笔记就是围绕这个思路展开怎么从零搭一套基于 YOLOv11 的农作物叶片自动分割与病虫害识别系统包括数据集怎么准备、模型怎么训、参数怎么调、部署时哪些坑必须提前避开。适合已经会跑 Python、想把这个方向落地成可用工具的从业者也适合刚接触 YOLO 分割、想找一个完整农业场景练手的新手。2. 数据集与标注叶片分割任务的第一个分水岭2.1 为什么农业场景的分割标注比通用数据集难通用分割数据集COCO、ADE20K里标注对象边界清晰、光照均匀而农作物叶片图像天然带着几个麻烦叶片相互遮挡、病斑与健康组织颜色渐变、田间背景杂乱土壤、杂草、滴灌带。如果直接拿 COCO 预训练权重去微调模型很容易把「叶片轮廓」和「病斑区域」混为一谈。我一般会把标注拆成两个层级第一层是叶片整体轮廓leaf第二层是病斑区域lesion。YOLOv11 的实例分割支持多类别多边形标注所以一个叶片可以同时有 leaf 和 lesion 两个实例训练时模型会学习区分这两类掩码。这样推理阶段就能算出「病斑面积 / 叶片面积」这个比值比单纯给一个分类标签有用得多。常见做法是用 LabelMe 或 CVAT 做多边形标注导出 COCO 格式的 JSON再用 Ultralytics 自带的转换脚本转成 YOLO 分割格式。注意 YOLOv11 分割的标签格式是class_id x1 y1 x2 y2 ...归一化坐标不是检测的class_id cx cy w h转换时最容易在这里翻车。2.2 从 LabelMe 到 YOLO 分割格式的转换脚本import json import os from pathlib import Path # LabelMe 导出的 COCO JSON 转 YOLO 分割 txt # 输入: coco.json, 输出: labels/ 目录下每张图一个 txt def coco_to_yolo_seg(coco_json, output_dir, class_map): with open(coco_json, r, encodingutf-8) as f: data json.load(f) # 建立 image_id - 文件名的映射 img_info {img[id]: img for img in data[images]} # 按 image_id 聚合标注 ann_by_img {} for ann in data[annotations]: ann_by_img.setdefault(ann[image_id], []).append(ann) os.makedirs(output_dir, exist_okTrue) for img_id, anns in ann_by_img.items(): info img_info[img_id] w, h info[width], info[height] lines [] for ann in anns: cat_id ann[category_id] if cat_id not in class_map: continue cls class_map[cat_id] # segmentation 是 [[x1,y1,x2,y2,...]] 的列表 seg ann.get(segmentation, []) if not seg: continue for poly in seg: # 归一化并保留 6 位小数避免精度丢失 norm [] for i in range(0, len(poly), 2): norm.append(round(poly[i] / w, 6)) norm.append(round(poly[i1] / h, 6)) line f{cls} .join(map(str, norm)) lines.append(line) # 写文件文件名与图片同名 stem Path(info[file_name]).stem with open(os.path.join(output_dir, stem .txt), w) as f: f.write(\n.join(lines)) # 类别映射0leaf, 1lesion coco_to_yolo_seg(annotations.json, labels/train, {1: 0, 2: 1})这段脚本的核心逻辑是把 COCO 的segmentation多边形坐标按图像宽高归一化类别 ID 重映射成从 0 开始的连续整数。参数上要注意class_map必须和data.yaml里的names顺序一致否则训练时类别会错位。另外 LabelMe 导出的 COCO 有时segmentation是空列表标注时只画了矩形这种样本要提前过滤不然训练会报IndexError。2.3 data.yaml 的写法与数据集划分比例# data.yaml path: /data/leaf_disease train: images/train val: images/val test: images/test names: 0: leaf 1: lesion划分比例我一般用 7:2:1但农业数据有个特殊性同一片田、同一天的图像高度相似如果随机划分验证集里会出现和训练集几乎一样的图指标虚高。正确做法是按「田块 日期」分组划分保证验证集的图像来自不同田块或不同拍摄批次。这个细节在论文里经常被忽略但落地时直接决定模型在真实场景的泛化能力。提示如果数据集里 lesion 类样本远少于 leaf不要简单复制样本优先用 YOLOv11 的copy_paste和mosaic增强分割任务里这两个增强对小目标病斑提升明显。3. 训练 YOLOv11-seg从环境配置到超参调优3.1 环境配置与权重选择Ultralytics 的环境配置现在比以前简单很多Python 3.9 直接 pip 装就行。但农业场景经常要在没有外网的服务器上跑建议提前把权重文件下好放到本地。# 创建虚拟环境 conda create -n yolo11 python3.10 -y conda activate yolo11 # 安装 ultralytics会自动装 torch pip install ultralytics8.3.0 # 验证安装 yolo checks权重选择上yolo11n-seg.pt最轻适合边缘部署yolo11s-seg.pt和yolo11m-seg.pt精度更高适合服务器端。农业叶片分割的掩码细节比通用场景更敏感我一般从yolo11s-seg.pt起步如果 mAP50-95 的 mask 指标低于 0.35 再换 m。3.2 训练命令与关键参数含义yolo segment train \ modelyolo11s-seg.pt \ data/data/leaf_disease/data.yaml \ epochs200 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience30 \ cacheTrue \ device0 \ projectruns/leaf_seg \ nameexp1逐个说参数imgsz640是分割任务的常用输入尺寸如果病斑特别小可以提到 1024但显存占用会翻倍lr00.01是初始学习率配合lrf0.01做余弦退火农业数据集通常不大几千张学习率太高容易震荡patience30表示 30 轮没有提升就早停避免过拟合cacheTrue把图像缓存到内存小数据集能明显加速。训练过程中重点看三个指标metrics/mAP50-95(B)是检测框指标metrics/mAP50-95(M)是掩码指标农业场景里 M 指标比 B 指标更重要。如果 B 高 M 低说明模型能定位病斑但掩码边界不准这时候要检查标注质量而不是盲目加数据。3.3 小目标病斑的优化策略早期病斑在 640 分辨率下可能只有十几个像素YOLOv11 的 P3 特征层虽然对小目标友好但分割掩码的上采样倍数有限。我试过几个有效的手段一是把imgsz提到 1024二是开启overlap_maskTrue默认就是 True三是调整mask_ratio4为 2让掩码分辨率更高。# 小目标优化版训练命令 yolo segment train \ modelyolo11m-seg.pt \ data/data/leaf_disease/data.yaml \ imgsz1024 \ mask_ratio2 \ overlap_maskTrue \ epochs300 \ batch8 \ lr00.005 \ cos_lrTrue \ close_mosaic20close_mosaic20表示最后 20 轮关闭 mosaic 增强让模型在真实分布上收敛这个技巧在分割任务里对边界精度提升很明显。mask_ratio2会让掩码分支的计算量增加但病斑边缘的锯齿感会明显减少。4. 推理与后处理把掩码变成可用的病害面积4.1 推理脚本与结果保存from ultralytics import YOLO import cv2 import numpy as np model YOLO(runs/leaf_seg/exp1/weights/best.pt) results model.predict( sourcetest_images/, imgsz1024, conf0.25, iou0.5, saveTrue, save_txtTrue, projectruns/predict, nameleaf_test ) # 逐图计算病斑面积占比 for r in results: if r.masks is None: continue masks r.masks.data.cpu().numpy() # shape: (N, H, W) classes r.boxes.cls.cpu().numpy() leaf_area 0 lesion_area 0 for i, cls in enumerate(classes): area masks[i].sum() if int(cls) 0: leaf_area area elif int(cls) 1: lesion_area area ratio lesion_area / leaf_area if leaf_area 0 else 0 print(f{r.path}: 病斑占比 {ratio:.2%})conf0.25是置信度阈值农业场景里病斑和健康组织的对比度低阈值设太高会漏检我一般从 0.25 开始试如果漏检多降到 0.15。iou0.5是 NMS 的 IoU 阈值叶片相互遮挡时会有重叠框这个值可以适当提到 0.6。save_txtTrue会把掩码以多边形形式存成 txt方便后续做面积统计或可视化。4.2 掩码后处理去除毛刺与孔洞填充YOLOv11 输出的掩码是二值化的边缘经常有毛刺直接算面积会偏大。常见做法是用形态学操作清理import cv2 import numpy as np def refine_mask(mask, kernel_size5): 对单个掩码做开运算去毛刺 闭运算填孔洞 mask mask.astype(np.uint8) kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size, kernel_size)) # 开运算先腐蚀后膨胀去掉小毛刺 opened cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) # 闭运算先膨胀后腐蚀填充内部孔洞 closed cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel) return closedkernel_size5对应 1024 分辨率下约 5 个像素的毛刺如果病斑本身很小小于 20 像素kernel 要降到 3否则会把整个病斑腐蚀掉。这个后处理步骤在面积统计场景里几乎是必须的不做的话病斑占比会虚高 5% 到 10%。4.3 多类别掩码的叠加与可视化def visualize_result(image_path, result, save_path): img cv2.imread(image_path) if result.masks is None: cv2.imwrite(save_path, img) return masks result.masks.data.cpu().numpy() classes result.boxes.cls.cpu().numpy() # leaf 用绿色lesion 用红色 color_map {0: (0, 255, 0), 1: (0, 0, 255)} overlay img.copy() for i, cls in enumerate(classes): color color_map.get(int(cls), (255, 255, 0)) mask masks[i].astype(bool) overlay[mask] color # 半透明叠加 result_img cv2.addWeighted(overlay, 0.4, img, 0.6, 0) cv2.imwrite(save_path, result_img)可视化时把 leaf 和 lesion 用不同颜色叠加能直观看出模型有没有把病斑误判成叶片。如果红色区域大面积覆盖健康组织说明 lesion 类的标注边界太松需要回去修标注。5. 避坑与排查农业分割任务里最容易翻车的五件事5.1 掩码指标高但实际分割效果差现象训练日志里mAP50-95(M)到了 0.6但推理时病斑掩码边缘像狗啃一样。原因通常是验证集和训练集来自同一批次图像模型记住了背景纹理而不是病斑特征。解决方法是按田块分组重新划分数据集并且在验证时用saveTrue把掩码可视化出来逐张看不要只看数字。5.2 训练到一半 loss 突然变 NaN现象前 50 轮正常第 51 轮 box_loss 和 seg_loss 同时变成 NaN。原因多半是学习率太高加上某个 batch 里出现了异常标注比如多边形自交或坐标超出图像范围。解决方法是先用脚本检查所有标签文件的坐标是否在 0 到 1 之间然后把lr0降到 0.005 并开启ampFalse排除混合精度问题。5.3 推理时掩码和检测框对不上现象检测框位置正确但掩码偏移了几十个像素。这是imgsz和rect参数配合的问题YOLOv11 在rectTrue时会对图像做最小填充掩码还原时如果没考虑填充偏移就会错位。解决方法是在推理时设rectFalse或者用result.masks.xy直接取原图坐标不要手动缩放。5.4 病斑面积占比总是偏大现象肉眼看病斑只占叶片 10%脚本算出来 25%。除了前面说的毛刺问题还有一个常见原因是 lesion 掩码把叶片边缘的阴影也包进去了。解决方法是在标注规范里明确「病斑边界以变色区域为准不含阴影」并在后处理里加一步颜色校验只保留 HSV 空间中偏黄褐色的区域。5.5 模型在手机端部署后帧率骤降现象服务器上 1024 分辨率跑 30 FPS导出 ONNX 放到手机端只有 3 FPS。原因是分割模型的后处理掩码上采样和 NMS在移动端 CPU 上很耗时。解决方法是导出时用halfTrue做 FP16 量化或者换成yolo11n-seg.pt并把imgsz降到 640精度损失在农业场景里通常可以接受。6. 进阶技巧用 TTA 和类别加权把病斑召回率再提一档训练收敛之后如果发现某些病害类别比如早期锈病的掩码召回率始终上不去可以试两个进阶手段。第一个是测试时增强TTA在推理时对同一张图做水平翻转和多尺度缩放把多次预测的掩码做加权融合。Ultralytics 原生支持augmentTrue但分割任务的 TTA 需要自己写融合逻辑def tta_predict(model, img_path, scales[0.8, 1.0, 1.2]): 多尺度 TTA返回融合后的掩码列表 all_masks [] for scale in scales: results model.predict(img_path, imgszint(640 * scale), conf0.2, verboseFalse) if results[0].masks is not None: all_masks.append(results[0].masks.data.cpu().numpy()) if not all_masks: return None # 简单平均融合实际项目里建议按置信度加权 return np.mean(all_masks, axis0)第二个手段是在损失函数里给 lesion 类更高的权重。YOLOv11 默认对所有类别一视同仁但农业场景里病斑样本远少于叶片样本可以在data.yaml里用cls_pw参数做类别加权或者直接在训练时用fraction参数控制采样比例。我一般会把 lesion 的损失权重设成 leaf 的 2 到 3 倍召回率能提升 5 到 8 个百分点代价是误检率略微上升需要根据实际业务容忍度权衡。还有一个容易被忽略的点是输入分辨率的选择。很多教程默认 640但农业叶片图像的病斑在 640 下可能只有 8 到 10 个像素分割掩码根本学不出边界。如果显存允许直接上 1024 甚至 1280配合mask_ratio2掩码的 IoU 能从 0.4 提到 0.6 以上。代价是训练时间翻倍但农业场景对实时性要求通常没那么苛刻精度优先。最后说个我自己的习惯每次训完模型不要只看results.csv里的最终指标把val_batch0_pred.jpg和val_batch0_labels.jpg并排打开对比看模型预测的掩码和标注的差异在哪。这个动作花不了五分钟但能发现 80% 的标注问题和模型偏差。农业病虫害识别这个方向数据质量比模型结构重要得多YOLOv11 已经把模型这一侧的门槛降得很低了剩下的功夫都在数据和后处理上。希望帮到你。本文还有配套的精品资源点击获取
返回列表