news 2026/10/5 12:01:57

YOLOv11多光谱农业病虫害检测与计数系统实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOv11多光谱农业病虫害检测与计数系统实战

简介:本资源是一份面向农业AI开发者与计算机视觉初学者的实战型技术指南,聚焦YOLOv11在多光谱图像上的创新应用,系统解决农田场景下叶片精准分割与虫害自动计数两大核心难题。文档共40页PDF,结构完整、支持目录跳转与左侧大纲导航,涵盖YOLOv11算法原理、多光谱数据采集与预处理、U-Net/Mask R-CNN对比下的叶片分割实现、基于深度学习的虫害计数方法设计、端到端系统集成及真实农田/温室/果园三大场景实验分析。资源为单文件PDF(2.02MB),文字图表清晰,无显示异常,适合作为项目开发参考或课程拓展材料。已有101人学习下载,内容兼具理论深度与工程细节,提供可复现的模型优化策略、评估指标代码片段及系统架构图,助力读者快速构建轻量、鲁棒的农业病虫害智能监测方案。

1. 农业病虫害检测实战:YOLOv11多光谱叶片分割与虫害计数系统开发指南——这不是一个“升级版YOLO”的噱头,而是把红外+可见光图像真正喂进模型、让虫子数量自动落进Excel表格的闭环方案

你手上有果园无人机拍的多光谱图(比如R、G、B、NIR、RE三波段或五波段),但OpenCV阈值调到眼花也分不清早期褐斑病和自然叶缘焦枯;你用YOLOv8跑过单张RGB图,结果小蚜虫团被当成噪声滤掉,而整片黄化叶片又被误标成“严重虫害”——这不是模型不准,是输入没对齐农业真实信号。本指南讲的不是“换个权重就能用”,而是从多光谱数据预处理、YOLOv11专用通道适配、叶片掩膜引导的虫体精确定位,到最终按株/按叶输出带置信度的虫数统计表的全链路工程实现。适合已跑通YOLOv5/v8基础训练、但卡在农业场景落地的算法工程师和农技数字化项目实施人员;0基础小白慎入——这里不教Python安装,但会告诉你为什么YOLOv11的HCA-Net主干里第3个CBAM模块必须重写通道注意力权重归一化方式。


2. YOLOv11不是YOLOv10+1:为什么农业多光谱任务必须用它,而不是微调旧版本

2.1 YOLOv11的HCA-Net主干:为多光谱设计的通道交互机制

YOLOv11(Ultralytics官方未发布v11,当前社区指代基于Ultralytics v8.2+魔改的HCA-Net架构版本)的核心突破在于HCA(Hierarchical Channel Attention)模块。它不像SE-Net那样只做全局通道加权,而是分三级处理:

  • Level-1:对每个光谱波段(如R/G/B/NIR/RE)单独计算局部感受野内的通道响应熵,识别该波段内“信息活跃区”;
  • Level-2:跨波段构建通道相似性图(Channel Similarity Graph),用余弦相似度矩阵量化NIR与RE波段在病斑区域的响应耦合强度;
  • Level-3:动态融合前两级输出,生成波段自适应权重向量——例如当NIR波段熵值高且与RE相似度>0.7时,自动提升NIR通道权重,抑制RGB中光照干扰强的G通道。

提示:这不是玄学。我们在苹果园褐斑病数据集上实测,HCA-Net比YOLOv8-C2f主干在NIR+RE双波段输入下,mAP@0.5提升4.2%,关键在小目标(<16×16像素蚜虫群)召回率从61.3%→79.8%。

2.2 多光谱输入适配:从5通道原始数据到YOLOv11可训张量

YOLOv11默认接受3通道输入,但农业多光谱影像常含5波段(如Sentinel-2的B02/B03/B04/B08/B11)。直接拼接会导致通道维度错乱。正确做法是:

import numpy as np import torch def multispectral_to_tensor(ms_img: np.ndarray, target_channels: list = ['R', 'G', 'B', 'NIR', 'RE'], channel_mapping: dict = None) -> torch.Tensor: """ ms_img: (H, W, C) numpy array, C=5 for typical agri multispectral target_channels: 指定输入模型的通道顺序,如['NIR','RE','R','G','B'] channel_mapping: {'NIR':0, 'RE':1, 'R':2, 'G':3, 'B':4} —— 原始影像波段索引映射 """ if channel_mapping is None: # 假设原始ms_img按[B,G,R,NIR,RE]顺序存储(常见于无人机多光谱相机) channel_mapping = {'B':0, 'G':1, 'R':2, 'NIR':3, 'RE':4} # 构建目标通道索引列表 idx_list = [channel_mapping[c] for c in target_channels] ms_slice = ms_img[:, :, idx_list] # (H, W, len(target_channels)) # 归一化:各波段独立min-max到[0,1],避免NIR数值远大于RGB导致梯度淹没 ms_norm = np.zeros_like(ms_slice, dtype=np.float32) for i in range(ms_slice.shape[-1]): band = ms_slice[:, :, i] p2, p98 = np.percentile(band, (2, 98)) # 防止异常值拉伸 ms_norm[:, :, i] = (band - p2) / (p98 - p2 + 1e-8) # 转torch tensor并调整维度 (C, H, W) tensor_img = torch.from_numpy(ms_norm.transpose(2, 0, 1)) return tensor_img # 示例:将5波段影像转为YOLOv11所需输入 raw_ms = np.load("apple_leaf_ms.npy") # shape: (1024, 1024, 5) input_tensor = multispectral_to_tensor( raw_ms, target_channels=['NIR', 'RE', 'R'], # 注意:这里只取3通道喂入,因YOLOv11默认3输入 channel_mapping={'NIR':3, 'RE':4, 'R':2} )

参数说明:

  • target_channels必须与YOLOv11配置文件中的nc(类别数)无关,它只决定输入张量通道顺序;
  • channel_mapping是关键——不同设备波段顺序不同(如MicaSense RedEdge是B,G,R,NIR,RE;DJI P4 Multispectral是G,R,RE,NIR,B),必须实地校准;
  • 为什么只取3通道?因为YOLOv11主干虽支持多通道,但Ultralytics训练框架仍以3通道为基准。我们采用“波段融合预处理”:将NIR与RE做差分增强病斑,再与R通道拼接,实际输入仍是3通道,但信息密度翻倍。

2.3 叶片分割与虫害计数的联合建模范式:Mask-Guided Bounding Box Refinement

传统做法是先分割叶片(用SegFormer),再在掩膜内检测虫体(用YOLOv8)。问题在于:分割误差会传导至检测框——若叶片边缘漏分割,虫体就可能落在背景里被过滤。YOLOv11提出Mask-Guided Refinement(MGR)机制:

  1. 主干提取多光谱特征后,分支1输出叶片语义分割图(1通道,0/1 mask);
  2. 分支2输出虫体检测框(xywh+class+conf);
  3. 关键步骤:用分支1的mask对分支2的特征图做逐像素加权(mask值越大,对应位置的虫体特征权重越高),再经轻量Refine Head输出最终框坐标。

这使模型学会“只在叶片区域内认真找虫”,而非全图搜索。我们在葡萄霜霉病数据集验证:MGR使误检率(背景误标为虫)下降37%,尤其对叶片背面反光区域效果显著。


3. 从数据准备到模型训练:YOLOv11多光谱农业检测的最小可行闭环

3.1 多光谱标注规范:为什么LabelImg不行,必须用Custom-Mask-Labeler

RGB图像标注可用LabelImg画矩形框,但多光谱下:

  • 同一病斑在NIR波段呈高亮,在RGB中可能是浅褐色,人工框选极易偏移;
  • 虫体常聚集在叶脉附近,需精确到像素级定位,矩形框会包含大量无虫背景,污染小目标学习。

我们采用半自动标注流程:

  1. 用ENVI打开多光谱影像,选取NIR波段做初始分割(Otsu阈值+形态学闭运算);
  2. 导出二值mask,在Python中用cv2.findContours提取叶片外轮廓;
  3. 对每个轮廓内区域,用skimage.segmentation.felzenszwalb做超像素分割;
  4. 人工在超像素块上点击标记“健康叶/病斑/虫体群”,生成带类别ID的mask图(uint16,0=背景,1=健康叶,2=褐斑,3=蚜虫群);
  5. 将mask图转换为YOLO格式:
    • 健康叶 → 不生成txt标签(仅用于MGR分支监督);
    • 病斑/虫体 → 每个连通域生成一个.txt行:class_id center_x center_y width height(归一化坐标)。

注意:虫体群必须标为单个目标(而非多个小框),因农业场景关注“每叶虫量”而非单虫定位。YOLOv11的MGR机制天然适配此粒度。

3.2 YOLOv11训练配置:关键参数与农业场景特调

YOLOv11的train.py需修改以下核心参数(基于Ultralytics v8.2.32魔改版):

# yolov11-agri.yaml # ------------------- # Model configuration nc: 2 # classes: 0=aphid_cluster, 1=downy_mildew_patch depth_multiple: 0.33 width_multiple: 0.50 # 使用HCA-Net主干,非默认C2f backbone: # [from, repeats, module, args] - [-1, 1, Conv, [64, 3, 2]] # 0 - [-1, 1, HCAStage, [128, 3]] # 1: HCA-Net Stage1, 3个HCA模块 - [-1, 1, HCAStage, [256, 6]] # 2 - [-1, 1, HCAStage, [512, 9]] # 3 - [-1, 1, HCAStage, [1024, 3]] # 4 # MGR分支配置 head: - [-1, 1, MGRHead, [nc, 3]] # nc classes, 3 channels for mask guidance

训练命令:

yolo train \ data=datasets/agri-ms/data.yaml \ model=yolov11-agri.yaml \ epochs=300 \ batch=16 \ imgsz=640 \ name=yolov11_agri_ms_v1 \ cache=True \ workers=8 \ optimizer=AdamW \ lr0=0.001 \ lrf=0.1 \ cos_lr=True \ augment=True \ hsv_h=0.015 \ hsv_s=0.7 \ hsv_v=0.4 \ translate=0.1 \ scale=0.5 \ shear=0.0 \ perspective=0.0 \ flipud=0.0 \ fliplr=0.5 \ mosaic=1.0 \ mixup=0.1 \ copy_paste=0.1

参数说明:

  • imgsz=640:多光谱影像分辨率通常≥1280×960,但YOLOv11的HCA-Net对显存敏感,640是平衡精度与速度的起点;实测1280输入使batch size需降至4,收敛变慢;
  • mosaic=1.0+mixup=0.1:强制开启马赛克增强,因农业图像背景复杂(枝干/土壤/天空),马赛克能提升模型对遮挡鲁棒性;
  • hsv_s=0.7:大幅增强饱和度扰动——多光谱中病斑常表现为色度异常,此参数迫使模型关注HSV空间而非RGB;
  • copy_paste=0.1:对虫体群做复制粘贴增强,解决田间采集时虫体分布不均问题。

3.3 训练过程监控:如何判断YOLOv11是否真在学“多光谱特征”

不要只看results.csv里的mAP。农业场景需验证三个隐性指标:

监控项正常表现异常信号排查动作
NIR通道梯度幅值训练中后期,NIR对应输入通道的梯度均值稳定在RGB通道的1.8~2.5倍NIR梯度持续低于RGB检查channel_mapping是否颠倒波段顺序;确认NIR波段是否被错误归一化(如用了全局min-max而非分波段)
MGR分支mask loss从epoch 50起,mask BCE loss < 0.15且平稳loss > 0.3且震荡检查标注mask是否为uint8(YOLO要求),而非float32;确认data.yaml中train路径指向mask图目录而非RGB图目录
小目标召回曲线在val集上,面积<256px²的目标召回率(R@0.5)随epoch单调上升至>75%R@0.5在epoch 100后停滞在50%启用--multi-scale(训练时动态缩放),或在yolov11-agri.yaml中将neck部分的SPPF替换为ASPP(空洞卷积金字塔)

4. 避坑:YOLOv11多光谱农业检测的5个血泪经验

4.1 现象:模型在训练集mAP@0.5达89%,但部署到无人机实时推理时,虫体检测框全部漂移到叶片外侧

原因:训练时使用了mosaic=1.0,但推理时未关闭mosaic(YOLOv11默认推理启用test-time augmentation,其中包含mosaic)。mosaic会将叶片切片拼接,导致模型学到“虫总在拼接缝附近”的虚假规律。
解决:推理前强制关闭TTA:

model = YOLO("yolov11_agri_ms_v1.pt") results = model.predict(source="test_ms.npy", tta=False) # 关键!

4.2 现象:同一片叶子,NIR波段标注的虫体框在RGB波段看根本不存在,但模型仍高置信度输出

原因:标注时未对齐波段——NIR与RGB存在亚像素级配准误差(无人机多光谱相机各波段镜头视差)。直接在NIR上框选,再映射到RGB会偏移。
解决:用ENVI的Image Registration工具,以R波段为基准,对NIR/RE波段做仿射配准(affine registration),保存配准后影像再标注。配准残差需<0.3像素。

4.3 现象:训练loss曲线正常下降,但验证集PR曲线中Recall在0.5阈值处突然坍塌(从85%→32%)

原因:data.yaml中val路径指向了未做多光谱预处理的原始RGB图目录,而非经过multispectral_to_tensor()处理的5波段npy文件。模型用5通道权重读3通道图,导致特征提取崩溃。
解决:严格区分数据路径——train和val必须指向同一预处理流程生成的.npy文件目录,且文件名与RGB图一一对应(如IMG_001.npy,IMG_002.npy)。

4.4 现象:YOLOv11推理速度比YOLOv8慢40%,GPU显存占用翻倍

原因:HCA-Net的Level-2通道相似性图计算(5波段需计算10组余弦相似度)在torch.einsum中未做CUDA kernel优化,导致CPU-GPU频繁同步。
解决:重写HCAStage中的相似性计算部分,用torch.cdist替代einsum:

# 原低效写法 sim_matrix = torch.einsum('bchw,bcij->bhwij', feat1, feat2) # O(N^4) # 替换为 feat_flat = feat1.flatten(2) # (B, C, H*W) sim_matrix = 1 - torch.cdist(feat_flat.permute(0,2,1), feat_flat.permute(0,2,1), p=2) # O(N^2)

4.5 现象:虫害计数结果波动大,相邻两帧同一叶片虫数从12跳到37

原因:未启用--agnostic-nms(类别无关NMS)。当模型同时输出“蚜虫群”和“粉虱群”时,NMS会将重叠框按类别分别抑制,但农业场景只需总数,跨类别重叠应合并。
解决:推理时添加参数:

yolo predict model=yolov11_agri_ms_v1.pt source=test/ --agnostic-nms --conf=0.3

5. 虫害计数系统落地:从YOLOv11输出到农事决策表的端到端管道

5.1 推理结果结构化解析:把bbox坐标转成“每叶虫量”统计

YOLOv11的results对象默认输出boxes.xyxy(左上右下坐标),但农业需求是“某片叶子上有几个虫群”。需结合叶片分割mask做空间关联:

def count_per_leaf(results, leaf_mask: np.ndarray, min_iou=0.3, min_conf=0.4) -> dict: """ results: YOLOv11 inference result leaf_mask: (H, W) uint8 array, 1=leaf, 0=background Returns: {leaf_id: {'aphid_count': int, 'mildew_area_ratio': float}} """ # Step 1: 获取所有虫体检测框(置信度过滤) boxes = results[0].boxes.xyxy.cpu().numpy() # (N, 4) confs = results[0].boxes.conf.cpu().numpy() classes = results[0].boxes.cls.cpu().numpy() valid_boxes = boxes[(confs > min_conf) & (classes == 0)] # 0=aphid_cluster # Step 2: 对leaf_mask做连通域分析,获取每片叶子的mask leaf_labels = cv2.connectedComponents(leaf_mask)[1] leaf_ids = np.unique(leaf_labels)[1:] # skip background (0) # Step 3: 对每个leaf_id,计算其mask与每个虫框的IoU leaf_stats = {} for lid in leaf_ids: leaf_mask_i = (leaf_labels == lid).astype(np.uint8) leaf_area = leaf_mask_i.sum() # 计算该叶片内虫体数:框中心点落在leaf_mask_i内,且IoU>min_iou count = 0 for box in valid_boxes: x1, y1, x2, y2 = map(int, box) # 裁剪框区域 box_roi = leaf_mask_i[y1:y2, x1:x2] if box_roi.size == 0: continue iou = box_roi.sum() / ((x2-x1)*(y2-y1) + 1e-8) if iou > min_iou: count += 1 leaf_stats[lid] = { 'aphid_count': count, 'leaf_area_px': leaf_area, 'leaf_area_cm2': leaf_area * 0.0025 # 假设1px=0.05mm,换算为cm² } return leaf_stats # 使用示例 leaf_mask = cv2.imread("IMG_001_leaf_mask.png", cv2.IMREAD_GRAYSCALE) results = model.predict(source="IMG_001.npy", verbose=False) stats = count_per_leaf(results, leaf_mask) print(f"叶片1虫数: {stats[1]['aphid_count']}, 面积: {stats[1]['leaf_area_cm2']:.2f} cm²")

5.2 生成农事决策表:按株聚合与阈值告警

果园管理需知道“哪棵树该打药”。我们将单叶统计聚合成单株:

树ID叶片数平均每叶虫数最高单叶虫数是否告警推荐措施
T001428.327是(>15)3天内喷施吡虫啉
T002382.19否7天后复查
import pandas as pd def generate_decision_table(leaf_stats_dict: dict, tree_mapping: dict, # {leaf_id: tree_id} threshold_per_leaf=15) -> pd.DataFrame: # 按树ID聚合 tree_data = {} for leaf_id, stats in leaf_stats_dict.items(): tree_id = tree_mapping.get(leaf_id, "UNKNOWN") if tree_id not in tree_data: tree_data[tree_id] = {'leaf_count':0, 'total_aphids':0, 'max_per_leaf':0} tree_data[tree_id]['leaf_count'] += 1 tree_data[tree_id]['total_aphids'] += stats['aphid_count'] tree_data[tree_id]['max_per_leaf'] = max( tree_data[tree_id]['max_per_leaf'], stats['aphid_count'] ) # 构建DataFrame rows = [] for tree_id, data in tree_data.items(): avg_per_leaf = data['total_aphids'] / data['leaf_count'] if data['leaf_count'] else 0 alarm = data['max_per_leaf'] > threshold_per_leaf action = "3天内喷施吡虫啉" if alarm else "7天后复查" rows.append({ '树ID': tree_id, '叶片数': data['leaf_count'], '平均每叶虫数': round(avg_per_leaf, 1), '最高单叶虫数': data['max_per_leaf'], '是否告警': '是' if alarm else '否', '推荐措施': action }) return pd.DataFrame(rows) # 输出Excel供农技员使用 df = generate_decision_table(stats, tree_map) df.to_excel("pest_decision_T20240515.xlsx", index=False)

5.3 系统级技巧:用YOLOv11的--save-conf与--save-crop实现可追溯质检

农业监管要求“谁在何时何地检测出多少虫”。YOLOv11的--save-conf会保存每个框的置信度,--save-crop则保存裁剪出的虫体图。我们组合使用:

yolo predict \ model=yolov11_agri_ms_v1.pt \ source=field_batch/ \ --save-conf \ --save-crop \ --project=agri_output \ --name=20240515_apple_orchard \ --conf=0.3 \ --iou=0.5 \ --agnostic-nms

生成目录结构:

agri_output/20240515_apple_orchard/ ├── labels/ # 每张图的txt,含conf字段 ├── crops/ # 按类别分文件夹,如crops/aphid_cluster/IMG_001_0.jpg ├── predictions/ # 可视化图,带置信度标签 └── metadata.json # 记录运行时间、GPU型号、输入参数

关键技巧:在crops/aphid_cluster/中,我们用EXIF写入GPS坐标(从无人机日志提取)和拍摄时间:

from PIL import Image, ExifTags from PIL.ExifTags import TAGS def add_exif_to_crop(crop_path: str, gps_info: dict, timestamp: str): img = Image.open(crop_path) exif = img.getexif() # 添加GPS信息(示例) exif[34853] = gps_info # GPSInfo tag exif[36867] = timestamp # DateTimeOriginal img.save(crop_path, exif=exif)

这样,农技员手机扫描虫体图二维码,就能看到“此蚜虫群于2024-05-15 10:23:41 拍摄于东经116.321°北纬39.912°,置信度0.87”。

我做这套系统时踩过最深的坑,是以为“多光谱=多通道输入”,结果发现波段配准误差0.5像素就让模型学偏——后来我们给每台无人机都做了出厂级波段校准,并把校准参数固化进预处理脚本。现在新项目启动,第一件事不是写代码,而是带着ENVI和标定板去果园做配准。农业AI没有银弹,只有把光学、农学、工程拧在一起的笨功夫。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 12:00:08

基于Scrapy的B站数据采集与可视化系统实战解析

这两年接了不少数据采集类的需求&#xff0c;但真正让我觉得“这项目值得复盘”的&#xff0c;还是这套基于 Scrapy 的 B 站数据分析可视化系统。从选题、抓取、清洗、入库到出图、出报告&#xff0c;整个链路一个人打通&#xff0c;技术选型和踩坑路径都比较典型&#xff0c;拿…

作者头像 李华
网站建设 2026/10/5 12:00:00

动力电池二阶RC模型+RLS在线辨识实战指南

1. 项目概述&#xff1a;为什么动力电池建模必须用二阶RCRLSSimulink这套组合拳&#xff1f;动力锂电池不是一块简单的“充电宝”&#xff0c;它是新能源汽车的“心脏”&#xff0c;是储能系统的“能量中枢”。你给它充一次电&#xff0c;它要扛住电机瞬时300A的放电冲击&#…

作者头像 李华
网站建设 2026/10/5 11:55:00

Trading-as-Git:本地化量化交易操作系统的版本化与风控闭环实践

1. 项目概述&#xff1a;这不是又一个“AI喊单机器人”&#xff0c;而是一套可版本化、可审计、可回滚的本地量化交易操作系统 你有没有过这种经历&#xff1a;深夜盯着K线图&#xff0c;手抖着点下实盘按钮&#xff0c;结果策略逻辑里藏着一个没发现的未来函数&#xff0c;或者…

作者头像 李华
网站建设 2026/10/5 11:53:51

零基础入门Java Web:从环境搭建到第一个Servlet项目全解析

很多零基础入门的朋友第一次看到“java Web”这个词&#xff0c;脑海里冒出来的问题往往是一连串的&#xff1a;Java 和 Java Web 是一回事吗&#xff1f;我学完了 Java 基础语法&#xff0c;接下来该怎么走&#xff1f;为什么书上第一章要花那么大篇幅讲环境配置、讲 Tomcat、…

作者头像 李华
网站建设 2026/10/5 11:52:06

大厂Java面试全攻略:从核心基础到微服务架构构建

每年春招秋招之前&#xff0c;我身边总有一批准备冲击大厂的Java工程师来约模拟面试。做得多了之后&#xff0c;我发现一个特别普遍的现象&#xff1a;很多人基础知识背得滚瓜烂熟&#xff0c;HashMap源码、JVM内存模型、Spring Bean生命周期张口就来&#xff0c;但面试官一旦把…

作者头像 李华
网站建设 2026/10/5 11:51:48

YOLOv8电梯异常行为检测实战:手挡门/脚卡缝/异物滞留实时识别

简介&#xff1a;本资源是一套基于YOLOv8实现的社区电梯故障预警系统完整工程包&#xff0c;面向计算机、人工智能、自动化等专业本科生及初阶开发者&#xff0c;解决电梯运行异常&#xff08;如轿厢异物、人员跌倒、门区滞留等&#xff09;的实时视觉检测与预警问题&#xff0…

作者头像 李华