YOLOv11叶片病虫害实时诊断:从训练到Jetson Nano部署
发布时间:2026/9/30 3:25:49来源:尧图网络
简介面向智慧农业与计算机视觉学习者的YOLOv11作物叶片病虫害实时诊断系统开发文档完整呈现从算法原理到系统落地全过程。内容覆盖YOLO系列发展历程、YOLOv11骨干网络与检测头设计、损失函数以及数据采集与标注、模型训练与优化、实时诊断系统前后端开发、模型部署、系统测试与评估并给出大型农场、小型农户、科研机构等五个实际应用案例适合农业工程、AI落地开发者作为项目参考。资源为1个PDF文件压缩包约2.03MB共38页支持目录章节跳转和阅读器大纲快速定位。目前已有60人学习适合需要快速理解作物病虫害实时诊断系统设计与YOLOv11实战应用的读者。1. 智慧农业里「叶片病虫害诊断」这件事为什么值得用 YOLOv11 重做一遍种过地的人都明白叶片病虫害最怕的不是病害本身而是发现得太晚。大棚里几百亩作物靠人工巡田走一圈下来腰都直不起来等看到病斑扩散减产已经是定局。智慧农业这几年喊得响但真正落到田间的多数还是温湿度传感器真正能「看见」叶片病害的系统少之又少。YOLOv11 这类实时目标检测模型的出现把这件事的成本结构改变了一个几百块的摄像头加一块边缘开发板就能在叶片上跑出每秒几十帧的检测结果病斑、虫眼、霉层框出来实时报警。这套系统的核心不是模型多先进而是「实时」两个字——边采集边诊断不等照片攒够再批处理。这篇落地笔记写给两类人一类是农学背景、想用现成算法做产品的开发者另一类是算法工程师想找个真实场景验证 YOLOv11 的训练与部署能力。我会按一条完整链路讲环境怎么搭、数据怎么备、小目标怎么调、模型怎么部署到 Jetson Nano、哪些坑会翻车以及最后怎么把「识别」升级成「持续监测」。2. YOLOv11 环境配置与叶片数据集准备先让训练跑得起来2.1 YOLOv11 环境配置CUDA、PyTorch 与 ultralytics 的版本怎么配才不玄学YOLOv11 不是独立发布的推理框架它由 ultralytics 这个统一 API 承载。老用户对这类的生态应该很熟YOLOv8、YOLOv9、YOLOv10 到 YOLOv11训练、验证、导出、部署全走同一个yolo命令行入口。这个统一入口的好处是你不需要为了新版本重写一套工程代码坏处是版本匹配一旦出错报错信息会让人误以为显卡坏了。先给一套我反复用过的环境组合。操作系统用 Ubuntu 20.04 或 22.04Python 用 3.8 到 3.10PyTorch 用 2.x 系列CUDA 按 PyTorch 的要求装 11.8 或 12.1。不建议直接用最新版 PyTorch因为 ultralytics 的某些算子在新版上会撞出莫名其妙的 OOM。下面这套命令是我每次新建训练机都会跑的# 创建虚拟环境避免和已有的 tensorflow / paddle 项目互相污染 conda create -n yolo11 python3.10 -y conda activate yolo11 # 安装 PyTorch这里用 CUDA 11.8 的版本稳定性和兼容性都更可控 # 如果显卡驱动只支持更低版本把 cu118 换成 cu113 或 cu121 pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118 # 安装 ultralytics 主库YOLOv11 的权重和训练命令都由它提供 pip install ultralytics8.3.0 # 验证环境是否通了下载预训练权重并跑通一次 CPU/GPU 推理 yolo predict modelyolo11n.pt sourcehttps://ultralytics.com/images/bus.jpg device0环境这一步的「玄学」通常出在 torch 与 CUDA 的匹配上。torch.cuda.is_available()返回 False多数不是显卡驱动的问题是 torch 编译时用的 CUDA 版本和驱动不兼容。装完后用nvidia-smi看驱动支持的 CUDA 版本再回到 PyTorch 官网选对应 whl 包十次里有九次能救回来。另一点容易忽略的是 numpy 版本。ultralytics 8.x 对 numpy 的版本有范围限制装得太新会出现np.int属性报错。如果遇到直接pip install numpy2.0降级。这套环境配好后建议立刻训练一个 dummy 任务验证反向传播别等数据准备好了才发现训练阶段就崩。2.2 作物叶片数据集从哪来公开集、自采标注与 VOC 转 YOLO 格式训练叶片病虫害模型数据比模型参数更重要。公开数据集里PlantVillage 这类叶片病害集是入门首选类别覆盖稻瘟病、锈病、叶斑病等常见种类但它的照片多数是单叶平铺在纯色背景上拍的和你大棚里实际看到的复杂背景差距很大。用这种数据训练出来的模型在实验室测试精度很高一到田间就露馅原因在于它没学到「在杂草、泥土、其他叶片遮挡下区分病斑」的能力。我的建议是公开集做预训练自采数据做二次微调。自采数据不用追求数量先拍够每个类别 200 到 500 张重点拍不同光照、不同角度、不同生长阶段的叶片。拍摄时把手机固定在支架上镜头距离叶片 30 到 50 厘米保证病斑直径在画面里占 20 像素以上——低于这个尺寸后续检测会非常吃力。标注工具用 LabelImg 或 X-AnyLabeling 都行导出格式选 PASCAL VOC也就是每张图配一个 XML 文件。YOLO 训练需要的是 txt 文件坐标格式是归一化的class_id x_center y_center width height所以中间要写一个转换脚本。这里给一个可以直接跑通的版本import xml.etree.ElementTree as ET import os from pathlib import Path # VOC 格式的 XML 转 YOLO 格式的 txt # 目录结构要求 # dataset/ # annotations/ # 存放所有 xml # images/ # 存放所有 jpg/png # labels/ # 脚本自动生成存放 txt def voc_to_yolo(xml_path, out_dir, class_names): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 转成 YOLO 的归一化中心点 宽高格式 x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_names.index(name)} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_path Path(out_dir) / (Path(xml_path).stem .txt) with open(out_path, w) as f: f.write(\n.join(lines)) class_names [healthy, rust, blight, mildew] # 按你的标注类别名改 xml_dir dataset/annotations txt_dir dataset/labels os.makedirs(txt_dir, exist_okTrue) for xml_file in Path(xml_dir).glob(*.xml): voc_to_yolo(str(xml_file), txt_dir, class_names)这段脚本有个容易被忽略的细节XML 里的坐标是绝对像素值YOLO 要的是相对图像宽高的比例不归一化的话训练时边界框会全部偏到图像一角损失函数直接发散。另外class_names列表的顺序必须和后面data.yaml里的类别顺序完全一致顺序错位是这类转换里最隐蔽的错误——训练不报错但预测结果张冠李戴。数据集准备好后还需要一份data.yaml内容大致是path: dataset/ train: images/train val: images/val nc: 4 names: [healthy, rust, blight, mildew]这里建议先按 8:2 划分训练集和验证集划分时用脚本按目录整体移动不要手动拖文件。叶片数据集的采集成本高每一张图都要珍惜划分前先检查有没有重复图片——用 MD5 去重否则验证集里混进训练图的副本精度虚高得很厉害。3. YOLOv11 叶片病虫害训练与调参小目标不翻车的几个必调项3.1 小目标优化病斑只有十几个像素时imgsz 和 mosaic 怎么选叶片病虫害检测和通用物体检测最大的不同在于目标尺寸分布极其极端。一片叶子在画面里可能占 30% 的面积但上面的锈病孢子堆只有十几个像素。YOLOv11 的主干网络下采样倍率通常在 32 倍左右一个 640×640 的输入特征图上每个格子对应原图 32×32 像素的区域。病斑目标小于这个尺寸时基本就退化成了特征图上的一个点检测头想把它从背景里分出来全靠运气。优化小目标我常用的手段按优先级排序第一把训练输入分辨率从默认的 640 提到 960 或 1280第二关闭或降低 mosaic 增强的概率第三用切片数据增强把小目标放大第四推理时用 SAHI 这类切片推理工具把大图切成重叠小块分别检测再合并。这里先讲前两个因为这俩是在训练命令里直接调的。mosaic 增强的本意是让模型看到更多上下文把四张图拼成一张。但对小目标来说mosaic 拼接时每张图被缩放到原来的 1/4原本就小的病斑再缩一次直接变成亚像素级等于把标注抹掉了。YOLOv11 的训练参数里有两个相关的开关mosaic0.5表示有 50% 的概率应用 mosaicclose_mosaic10表示最后 10 个 epoch 强制关闭 mosaic。后者的逻辑是让模型在最后的收敛阶段回归到正常的分布上这个设计非常关键。分辨率提升带来的副作用是显存占用变大。如果你的显卡只有 8GB 显存imgsz1280大概率会 OOM训练时可以用batch8甚至batch4配合梯度累积。这里给出我常用的一个训练命令里面不只有小目标相关的参数还有一批稳定训练的配置yolo train \ modelyolo11s.pt \ dataleaf.yaml \ epochs200 \ imgsz960 \ batch16 \ mosaic0.5 \ close_mosaic10 \ optimizerSGD \ lr00.01 \ weight_decay0.0005 \ patience30 \ projectruns/leaf \ nameexp_smallobj \ device0imgsz960是小目标场景最值得的改动带来的 mAP 提升通常比换更大的 backbone 还明显。modelyolo11s.pt是从预训练权重开始微调不建议从随机权重开始训叶片数据和 COCO 这种自然图像分布接近迁移学习能省一半以上的训练时间。patience30表示验证集指标连续 30 个 epoch 不涨就早停这是防止无效训练占着显卡的保险丝。一个容易忽略的细节是optimizer的选择。ultralytics 默认用 auto会自动选 AdamW。但对叶片这类数据量不夸张的任务我用 SGD 反而更稳收敛慢一点但最终精度更高也不容易在训练后期震荡。lr0保持 0.01 就行设置了close_mosaic10之后模型在最后几个 epoch 的 loss 会短暂回升再下降这是正常现象别看到 loss 突涨就手动终止。3.2 训练过程怎么盯验证指标、混淆矩阵与模型的保存路径训练不是把命令丢进去就完事的。叶片病虫害诊断的错误代价很高——漏检一个病斑等于让病害多扩散一轮。所以训练过程中要看的不只是 mAP更要看每一个类别各自的查全率。YOLOv11 训练完会在runs/leaf/exp_smallobj/下生成一批文件其中三样必看第一是results.png左上角两张子图分别是训练 loss 和验证 loss右下角是验证集的 mAP50 和 mAP50-95。重点看验证 loss 有没有在训练后期和训练 loss 拉开差距如果越来越大说明过拟合开始需要回退到表现最好的那个 epoch 权重或者加数据增强。第二是confusion_matrix.png它会告诉你每个类别之间互相混淆的程度。叶片场景里最常见的混淆是「健康叶片」和「早期病斑」分不开因为病斑初期颜色变化不明显。如果混淆矩阵里健康叶片那一行有大量样本被分到病斑类说明你的阈值定得太宽推理时可以调高conf参数压制误报。第三是val_batch_pred.jpg这是验证集图像的预测可视化。别只看指标要看框和真实病斑的重合度。YOLO 的边界框通常比病斑实际范围大一圈但如果你发现框的位置偏在病斑边缘而不是中心大概率是标注数据本身有系统偏差。训练完成后模型权重默认保存为best.pt和last.pt。best.pt是验证集 mAP 最高的那次last.pt是最后一个 epoch 的状态。部署时用best.pt但如果训练过程出现大波动建议把best.pt存一个备份别直接覆盖。我习惯把每次训练的数据集版本号和 yaml 配置一起存进runs目录的备份文件里等你想复现三个月前的精度时会发现这是最后的后悔药。3.3 验证与推理结果保存把预测写进图像之外的三种方式做智慧农业系统光有模型还不够得把预测结果落到产品能用的形态。YOLOv11 的预测命令默认把标注框画在图像上保存但实际项目里还要返回病斑的坐标、类别、置信度以及原始的裁剪小块。# 基本预测保存带标注的图像和对应的 txt 标签 yolo predict modelruns/leaf/exp_smallobj/weights/best.pt \ sourcedataset/images/val \ conf0.25 \ saveTrue \ save_txtTrue \ save_confTrue \ projectruns/predict \ nameleaf_val # 输出解释 # saveTrue 保存画框后的图像文件名和原图同名 # save_txtTrue 每个预测目标输出一行class_id x_center y_center width height conf # save_confTrue 在 txt 里追加置信度便于下游按阈值过滤这里conf0.25是默认阈值但叶片场景建议推理时用conf0.3左右。病斑检测的代价是漏检大于误报阈值太低会引入大量背景误检太高会漏掉早期病斑。实际项目里我会跑两遍推理一遍用低阈值做筛查一遍用高阈值做报警两个结果合并不是简单取交集而是按病斑面积和置信度加权计分。txt 标签文件是给后端用的但前端展示还是需要图像。如果你要把中文类名画到图上直接套用默认的绘图逻辑会乱码这个坑在第 5 章专门讲。单纯跑预测只是第一步真正的实时系统需要把这段逻辑嵌进视频流循环里这是下一章的主题。4. 实时诊断与部署从摄像头采集到 Jetson Nano 边缘推理4.1 实时推理脚本摄像头帧读取、帧率控制与结果落盘从静态图片到实时视频流差的不是模型是工程。摄像头的输出帧率是 25 到 30 FPS但 YOLOv11s 在普通 PC 上推理一张 960×960 的图像大约要 30 到 50 毫秒如果每帧都做完整推理CPU 会持续满载系统也没余力做数据上传和报警。常见的做法是控制推理频率比如每 3 帧抽 1 帧做检测中间两帧直接沿用上一次的检测结果视觉上几乎无感。下面这个脚本基于 OpenCV 和 ultralytics跑通摄像头实时推理、结果保存和帧率显示直接可以作为一个最小系统起点import cv2 from ultralytics import YOLO # 加载训练好的权重推理时模型会被自动切换到 eval 模式 model YOLO(runs/leaf/exp_smallobj/weights/best.pt) # 0 表示默认摄像头大棚场景通常用 RTSP 流把 0 换成 rtsp://ip:554/stream1 即可 cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) frame_id 0 while cap.isOpened(): ret, frame cap.read() if not ret: break # 每 3 帧推理一次其余帧直接复制上一帧的结果框降低 GPU/CPU 占用 if frame_id % 3 0: results model.predict(frame, conf0.3, imgsz960, verboseFalse) boxes results[0].boxes # 当前帧的检测框集合 else: pass # 实际项目中在这里绘制上一帧的 boxes # 画框和类别文字ultralytics 自带 plot() 方法返回 BGR 图像 annotated results[0].plot() if frame_id % 3 0 else frame # 计算并显示实时帧率方便现场调参时观察系统负担 fps cap.get(cv2.CAP_PROP_FPS) cv2.putText(annotated, fFPS: {fps:.1f}, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imshow(leaf-diag, annotated) # 按 q 退出按 s 保存当前帧带检测结果的图用于事后复盘 key cv2.waitKey(1) 0xFF if key ord(q): break elif key ord(s): cv2.imwrite(foutput/frame_{frame_id}.jpg, annotated) frame_id 1 cap.release() cv2.destroyAllWindows()model.predict()的参数和训练时是独立的imgsz960在推理时会先把输入 resize 到 960和训练分辨率不一致会导致精度下降建议推理imgsz和训练保持一致。verboseFalse必须设置否则每帧都会往控制台刷一堆检测日志远程调试时日志会被刷爆。这个脚本能跑通但离「系统」还差两块一是结果数据没有结构化输出只有图像上的框二是没有报警机制。实际项目里我会在检测到病斑时把class_id、坐标、置信度组装成 JSON通过 MQTT 推送到后端由后端决策是否触发短信或语音报警。边缘设备只负责「看」决策逻辑放在服务端这样模型更新时不用重刷每一台设备。4.2 部署到 Jetson Nano从 .pt 到 TensorRT engine 的完整路径Jetson Nano 是边缘部署里最常见的目标设备基于 ARM64 架构GPU 是 Maxwell 架构CPU 也是四核 ARM。直接在它上面跑 PyTorch 的.pt权重非常吃力必须先把模型转换成 TensorRT 的 engine 格式。TensorRT 做三件事层融合、精度校准、kernel 自动调优。层融合把卷积和激活合并成一层减少显存读写精度校准允许用 FP16 替代 FP32kernel 自动调优针对具体 GPU 选最快的实现。三步下来推理速度通常能翻一倍以上。转换流程是先把.pt导出成 ONNX再用 TensorRT 的trtexec工具把 ONNX 编译成 engine。中间不要直接用 ultralytics 的 export 一步到位虽然它支持直接导出 engine但在 Jetson 上经常因为 TensorRT 版本不匹配报错。# 在 PC 或 Jetson 上先导出 ONNXopset 用 12老版本 TensorRT 对高版本 opset 支持不好 yolo export modelruns/leaf/exp_smallobj/weights/best.pt formatonnx opset12 # Jetson 上用 trtexec 编译 engine # 固定输入尺寸 960x960避免动态 shape 带来的额外开销 # fp16 能显著提速但如果检测小目标先跑 fp32 对比一下精度再决定 /usr/src/tensorrt/bin/trtexec \ --onnxbest.onnx \ --saveEnginebest_fp16.engine \ --inputIOFormatsfp16:chw \ --outputIOFormatsfp16:chw \ --fp16 \ --minShapesimages:1x3x960x960 \ --optShapesimages:1x3x960x960 \ --maxShapesimages:1x3x960x960--minShapes、--optShapes、--maxShapes三个参数必须写一致这样生成的 engine 是静态 shape推理时不处理动态尺寸变化延迟最稳定。FP16 对小目标的精度损失是真实存在的尤其在病斑只有十几个像素的情况下我建议第一次部署先不启用--fp16跑通流程后再对比两个 engine 在验证集上的 mAP损失超过 0.5 就继续用 FP32。Jetson Nano 的内存只有 4GB运行 TensorRT engine 时建议关闭图形桌面纯命令行模式启动能省出近 1GB 内存。推理脚本里用tensorrt后端加载 enginefrom ultralytics import YOLO # 加载 engine 文件和加载 .pt 文件的接口一致 model YOLO(best_fp16.engine) results model.predict(frame, conf0.3, imgsz960, device0)加载 engine 后前面的摄像头推理脚本可以原样复用不需要改检测逻辑。唯一要注意的是Jetson 上的 OpenCV 默认不支持读取 RTSP 流需要重新编译带 GStreamer 支持的 OpenCV或者用v4l2src直接读取 USB 摄像头。这一步卡住很多人常见报错是Could not open video stream解决办法是先跑gst-launch-1.0 v4l2src device/dev/video0 ! autovideosink确认摄像头被系统识别如果这条命令都不过再去查摄像头驱动和权限。部署完成后别急着验收精度先跑一个小时的长时间推理脚本看有没有内存泄漏和温度降频。Jetson Nano 散热片摸上去烫手是常态但温度超过 85 度会触发降频推理帧率直接腰斩。给设备装一个小风扇比调任何参数都管用。5. 避坑叶片病虫害系统开发里的 5 个高频翻车点训练和部署跑通之后真正的麻烦才开始。这里列五个我在叶片病害项目里反复踩过的坑每条都按「现象 → 原因 → 解决」写给后来者当参考。坑一病斑小目标几乎全漏检但大目标的 mAP 高得离谱。现象验证集 mAP50 有 0.85 以上但可视化结果里所有病斑目标一个都没框出来框全落在叶片轮廓上。原因数据集里病斑标注框普遍小于 32×32 像素远低于 YOLO 特征图的有效感受野同时训练时开了默认的 mosaic 增强小目标被进一步缩小后直接消失。解决训练时imgsz960mosaic0.5close_mosaic10。如果还不行对所有标注框面积小于 32×32 的样本做裁剪放大——用脚本把病斑中心区域裁出来拼成新图重新标注相当于手动做一次小目标增强。这个操作能把小目标的 mAP 从 0.3 拉到 0.6 以上代价是数据集体积翻倍。坑二训练时 loss 正常收敛但推理时对健康叶片的误报率极高。现象训练曲线很漂亮mAP 也不低但部署到现场后摄像头扫过一片健康作物每分钟报十几条假警。原因训练集里「健康叶片」的背景样本不够模型没见过足够多「健康但姿态各异的叶子」把深绿色、有纹理的叶片误判为病斑。另一个原因是推理阈值设太低训练时用conf0.25但部署场景误报代价高阈值没跟着调。解决在训练集里加入大量健康叶片的「负样本」不要只拍干净的纯绿叶片要拍带露水、带泥土、带虫咬痕迹但无病害的叶片。推理时把conf调到 0.4 以上配合 NMS 的iou0.45误报能压下去一半。如果还压不住就单独训一个健康/病害二分类器做前置过滤。坑三中文类别名在保存的推理图上乱码。现象检测框和坐标都对但图像上方的标签显示成一串方块或者问号图片没法直接给农户看。原因OpenCV 的cv2.putText不支持中文ultralytics 内部绘图用的是 PIL 加载默认字体默认字体没有中文字形。这是 OpenCV/Pillow 的字体渲染问题和模型无关。解决不用默认的plot()画中文改用 PIL 加载系统里的中文字体文件比如思源黑体或文泉驿用ImageDraw.text()手动绘制标签。类别名在训练时可以直接用拼音或英文展示层再做中文映射例如rust显示为「锈病」这样模型权重文件没有中文到哪台设备上部署都不会乱码。坑四Jetson Nano 上推理延迟正常但整体系统经常卡死或无响应。现象单独跑推理脚本帧率正常但把摄像头采集、MQTT 上报、本地存储几个线程叠一起运行几十分钟后设备失去响应。原因Jetson Nano 只有 4GB 内存统一内存架构下 GPU 显存和系统内存共享。推理时图像和特征图占着内存视频帧又不停地往里塞内存耗尽后触发 OOM进程被内核杀掉。常驻线程之间用队列传数据没有做背压控制采集线程把队列塞爆。解决把摄像头采集和推理放进两个线程采集线程只保留最近 3 帧旧的直接丢弃不要用无界队列。MQTT 上报失败时要丢弃报错消息而不是重试堆积。跑通后长时间挂机测试观察/usr/bin/nvidia-smi里显存占用是否持续增长——如果增长就是哪一处数组只增不减基本是画框可视化时保存的历史帧列表没有释放。坑五导出的 ONNX 模型在 Jetson 上转换失败或转换后精度暴跌。现象PC 上推理正常trtexec转 engine 时报TRT - unknown ONNX operator或者转完精度从 mAP 0.8 掉到 0.4。原因ONNX opset 版本和 TensorRT 不匹配或者导出的模型里带上了端到端 NMS 层TensorRT 对自定义 NMS 的支持不完整。精度暴跌多半是启用了 FP16 时小目标的边界框回归数值精度不足导致的。解决导出时带opset12并加上nmsFalse参数让导出文件只含网络前向部分NMS 放到推理时在 TensorRT 之外用 Python/NumPy 实现。FP16 转换前先跑 FP32 版 baseline对比两类目标大叶片、小病斑分别的 AP确认损失可接受再上 FP16。叶片病害场景里少 0.5 个点的 mAP 可能就意味着一整片发病初期的病斑全部漏报这个精度换速度的交易要谨慎做。6. 进阶用目标跟踪和注意力改进把「识别」升级成「持续监测」实时诊断系统跑通后下一步自然的问题不再是「这片叶子上有没有病」而是「这棵作物从今天到明天病害扩散了多少」。这需要目标跟踪给每一个检测框分配稳定的 ID跨帧关联同一片叶子或同一个病斑。YOLOv11 配合 ByteTrack 是常见的做法ByteTrack 的核心是用检测框和上一帧轨迹做 IoU 匹配对低置信度框也有二次关联逻辑。在叶片场景下跟踪的价值不是省算力而是你终于能回答「病害发展速度」这个农艺问题而不仅是「当前有病」。from ultralytics import YOLO # 启用跟踪模式persistTrue 表示跨帧保持 ID model YOLO(best_fp16.engine) results model.track(frame, persistTrue, conf0.3, iou0.5, device0) # 每个框带一个稳定的 track_id按轨迹统计病斑面积变化 for box in results[0].boxes: cls_id int(box.cls[0]) track_id int(box.id[0]) if box.id is not None else -1 area (box.xyxy[0][2] - box.xyxy[0][0]) * (box.xyxy[0][3] - box.xyxy[0][1]) print(ftrack_id{track_id}, cls{cls_id}, area{area:.1f})跟踪跑通后可以按 track_id 统计同一病斑的面积扩张速度超过阈值就预警。但要注意叶片会随风摆动、遮挡交替出现track_id 断裂是常态不要期望一条轨迹贯穿全天。把 ID 断裂当作事件切分用「同一叶片多次出现时病斑面积的平均变化率」作为指标比追踪单条轨迹更抗噪。模型结构层面如果追求更高的检测精度YOLOv11 的改进空间主要集中在小目标和细粒度纹理上。冠层叶片病斑的边缘模糊注意力机制是主流的改进方向——HCANet 这类混合注意力思路值得参考它本质上是在通道注意力和空间注意力之外再引入上下文建模让模型不仅仅看「病斑区域」还参考「叶片环境和相邻组织的纹理差异」。加注意力模块的位置多数选在主干网络的深层输出和 neck 的跨尺度融合处加深的幅度控制在参数量的 10% 以内避免边缘设备推理掉帧。改进后的模型要做的第一件事不是看 mAP而是对比「小目标类别的 AP」和「推理延迟」。叶片场景的模型改进如果小目标 AP 没涨其他指标涨再多都是无效改进。部署前把改进前后的 engine 都跑一遍整套验证脚本用同一组测试集、同一套推理参数把指标差异记录到训练日志里。我习惯在每次改进前先冻结当前模型的权重、配置、数据集版本编号存档。哪怕只是调了一个mosaic概率也值得花十秒钟写进备注。否则两周后被现场反馈「召回率好像降了」时你会发现连当时跑的命令都找不到。这套系统从环境搭建到边缘部署每一步的坑都写在前面了保持这种记录习惯会帮你少走一半弯路。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网