☰
YOLOv11作物生长阶段识别:从检测到精准施肥决策实战
2026/9/30 4:51:54 网站建设 项目流程

简介:本资源为面向智慧农业方向的YOLOv11实战文档,适合计算机视觉学习者、农业信息化从业者及目标检测进阶读者,用于解决作物生长阶段识别与精准施肥决策的落地问题。文档共37页,以1个PDF文件交付,压缩包约2.3MB,支持目录章节跳转、阅读器左侧大纲显示与章节快速定位,查阅体验完整流畅。内容从智慧农业背景与作物识别意义切入,系统讲解YOLOv11核心架构与创新点,并展开数据集构建、标注与预处理、模型训练与优化、评估指标分析等关键环节;后半部分聚焦精准施肥决策算法设计、系统集成开发与Web端、移动端交互实现,最后通过实践案例评估识别准确率、施肥量与产量效益。已有54人学习,读者可借此掌握从数据到部署的完整技术链路与排错思路。

1. 从一株番茄的追肥难题说起:YOLOv11 怎么把作物生长阶段识别接进精准施肥决策

去年夏天,我在一个连栋温室里蹲了三天,就为了搞清楚一件事:为什么同一批定植的番茄,有的已经进入开花坐果期,有的还卡在苗期徒长。种植户老周凭经验追肥,结果一半植株氮肥过量疯长,另一半缺肥黄叶。这不是老周不勤快,而是人眼判断生长阶段这件事,本身就存在主观性和滞后性。智慧农业里常说的精准施肥决策,第一步不是算肥料配方,而是先准确知道每一株作物现在处于哪个生长阶段。这正是 YOLOv11 作物生长阶段识别要解决的问题——用目标检测模型在田间图像里框出植株,并分类它当前所处的生育期,再把阶段信息喂给施肥决策模块,输出该不该追肥、追什么肥、追多少。这套方案适合有基本 Python 和深度学习基础的农业信息化从业者、智慧农业项目开发者,以及想用视觉模型落地种植管理场景的工程师。它不要求你懂农学配方,但要求你能把模型跑通、把阶段映射表建对、把推理结果稳定地传给决策逻辑。

2. YOLOv11 识别作物生长阶段:从数据标注到模型选型的完整链路

2.1 为什么选 YOLOv11 而不是分类网络做生长阶段识别

很多人第一反应是:生长阶段识别不就是图像分类吗,用 ResNet 或 EfficientNet 不就行了。我一开始也这么想,直到在温室里拍了一组照片才发现问题。分类网络只能告诉你“这张图里有一株处于开花期的番茄”,但它不知道这株番茄在画面的哪个位置。而精准施肥决策往往需要定位到具体植株,尤其是当画面里同时存在多株不同阶段的作物时,分类网络直接失效。

YOLOv11 作为目标检测模型,输出的是边界框加类别。你可以把“番茄-苗期”“番茄-开花期”“番茄-坐果期”当作三个检测类别,模型在框出植株的同时完成阶段分类。这样做的好处是:第一,支持一图多株不同阶段的识别;第二,边界框可以裁剪出单株图像,方便后续做更细的形态分析;第三,YOLOv11 在保持实时性的同时,对小目标和遮挡场景比前代更稳,这在叶片交错的大田和温室里很关键。

选型上还有一个现实考量:YOLOv11 的生态成熟,Ultralytics 框架一条命令就能训练和导出,部署到 Jetson Nano 这类边缘设备也有现成路径。对于智慧农业项目来说,模型能不能在田间地头的低功耗设备上跑起来,比在服务器上刷高几个点 mAP 重要得多。

2.2 数据采集与标注:生长阶段类别怎么定、标多少张才够

数据是这套方案里最容易翻车的地方。我见过太多人拿公开数据集直接训,结果模型在自家温室里一塌糊涂。作物生长阶段识别对数据的要求有三个硬指标:光照多样性、株龄覆盖度、遮挡真实度。

先说类别定义。不要一上来就分十几个阶段,那会导致类别边界模糊、标注一致性差。我一般建议按施肥决策的实际需求来定,通常 4 到 6 类足够。以番茄为例:

阶段编号阶段名称施肥决策含义
0苗期控氮、促根
1营养生长期平衡肥、增氮
2开花期增磷钾、控氮
3坐果期高钾、补钙
4成熟期控水控肥、促转色

这个映射表是整条链路的灵魂。模型输出的类别不是终点,而是施肥决策模块的输入。类别定得不对,后面配方再准也没用。

标注数量上,每个类别至少 300 到 500 个实例,总图数 1500 到 2500 张起步。如果温室场景单一,可以少一些;如果大田多品种混种,建议翻倍。标注时用 LabelImg 或 CVAT 画框,框要贴紧植株冠层边缘,不要框到相邻植株。遇到严重遮挡的植株,宁可标 visible 部分,也不要凭想象补全。

采集时注意:早上、中午、傍晚各拍一轮,顺光逆光都要有,滴灌后叶片反光也要拍。这些“脏数据”才是模型在真实场景里不翻车的保障。

2.3 用 Ultralytics 训练 YOLOv11:配置文件与关键参数

环境配置是第一步。我习惯用 conda 建独立环境,避免和系统 Python 打架:

conda create -n yolo11_agri python=3.10 -y conda activate yolo11_agri pip install ultralytics==8.3.0 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121

装完后用yolo checks验证 CUDA 是否可用。如果显示 CPU only,检查显卡驱动和 CUDA 版本匹配。

数据目录按 YOLO 格式组织:

datasets/crop_stage/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml

data.yaml内容:

path: /home/user/datasets/crop_stage train: images/train val: images/val test: images/test nc: 5 names: ['seedling', 'vegetative', 'flowering', 'fruiting', 'maturity']

训练命令:

yolo detect train \ model=yolo11m.pt \ data=datasets/crop_stage/data.yaml \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ patience=30 \ device=0 \ project=runs/crop_stage \ name=exp_v1

参数说明:model=yolo11m.pt选中等规模,n 版太快但精度不够,l 版在 Jetson 上推理吃力;imgsz=640是精度和速度的平衡点,如果小目标多可以提到 1280,但显存要够;lr0=0.01初始学习率,配合lrf=0.01余弦退火到 0.0001;patience=30早停,避免过拟合。训练过程中重点看mAP50-95和各类别precision/recall,如果某个阶段 recall 明显低,多半是样本不均衡或标注边界模糊。

2.4 小目标与遮挡优化:让模型在田间不“瞎”

YOLOv11 本身对小目标做了改进,但作物场景里的小目标往往是刚出苗的植株或远处冠层,像素面积可能只有 20×20。我一般从三个方向优化:

第一,数据层面。在标注时对小于 32×32 的目标单独统计,如果占比超过 15%,训练时开启mosaic=1.0和scale=0.5,让模型多见小目标拼接场景。同时可以复制粘贴小目标实例,做简单增强。

第二,模型层面。把imgsz从 640 提到 960 或 1280,但注意推理速度会下降。如果部署在 Jetson Nano 上,建议用 640 训练、640 推理,靠数据增强补小目标。

第三,后处理层面。推理时把conf阈值从默认 0.25 降到 0.15,iou从 0.7 调到 0.5,减少漏检。但这样会引入误检,需要根据施肥决策的容错率来权衡。我的经验是:漏检一株开花期植株,可能导致少施一次磷钾肥;误检一株苗期为开花期,可能导致过早追肥。两者都有代价,通常漏检代价更大,所以宁可放宽conf。

from ultralytics import YOLO model = YOLO('runs/crop_stage/exp_v1/weights/best.pt') results = model.predict( source='field_images/', conf=0.15, iou=0.5, imgsz=640, save=True, save_txt=True, project='runs/predict', name='field_v1' )

这段推理脚本会把结果保存到runs/predict/field_v1,save_txt=True生成每张图的检测框坐标和类别,方便后续和施肥决策模块对接。conf=0.15是田间场景的保守值,如果误检太多再往上调。

3. 从检测框到施肥决策:阶段映射、决策表与推理结果保存

3.1 生长阶段到施肥配方的映射逻辑

模型输出的是类别 ID 和置信度,施肥决策模块需要的是“这株作物现在该不该追肥、追什么、追多少”。中间需要一个映射层。我一般用查表法加规则引擎,简单可靠,方便种植户理解和调整。

先定义每个阶段的施肥策略:

FERTILIZER_PLAN = { 'seedling': { 'action': '控氮促根', 'n_ratio': 0.2, 'p_ratio': 0.3, 'k_ratio': 0.3, 'amount_g_per_plant': 5, 'note': '避免徒长,侧重磷肥促根' }, 'vegetative': { 'action': '平衡追肥', 'n_ratio': 0.4, 'p_ratio': 0.2, 'k_ratio': 0.3, 'amount_g_per_plant': 15, 'note': '氮肥为主,配合磷钾' }, 'flowering': { 'action': '增磷钾控氮', 'n_ratio': 0.15, 'p_ratio': 0.35, 'k_ratio': 0.4, 'amount_g_per_plant': 20, 'note': '控制氮肥防止落花' }, 'fruiting': { 'action': '高钾补钙', 'n_ratio': 0.15, 'p_ratio': 0.15, 'k_ratio': 0.55, 'amount_g_per_plant': 25, 'note': '钾肥为主,叶面补钙防裂果' }, 'maturity': { 'action': '控水控肥', 'n_ratio': 0.1, 'p_ratio': 0.1, 'k_ratio': 0.2, 'amount_g_per_plant': 8, 'note': '减少施肥,促进转色' } }

这个表不是农学标准答案,而是我根据常见茄果类作物整理的可调模板。实际项目里要请农艺师按当地土壤检测结果和品种特性校准。关键点是:决策表要独立于模型,方便不改代码就能调整配方。

3.2 把 YOLOv11 推理结果接入决策模块的代码实现

推理结果保存后,下一步是解析检测框、统计每株作物的阶段、生成施肥建议。我一般写一个后处理脚本:

import os import cv2 from collections import defaultdict CLASS_NAMES = ['seedling', 'vegetative', 'flowering', 'fruiting', 'maturity'] def parse_yolo_txt(txt_path, img_w, img_h): detections = [] with open(txt_path, 'r') as f: for line in f: parts = line.strip().split() cls_id = int(parts[0]) cx, cy, w, h = map(float, parts[1:5]) x1 = int((cx - w / 2) * img_w) y1 = int((cy - h / 2) * img_h) x2 = int((cx + w / 2) * img_w) y2 = int((cy + h / 2) * img_h) detections.append({ 'class': CLASS_NAMES[cls_id], 'bbox': [x1, y1, x2, y2], 'area': (x2 - x1) * (y2 - y1) }) return detections def generate_fertilizer_advice(detections, plan): stage_count = defaultdict(int) for det in detections: stage_count[det['class']] += 1 advice = [] for stage, count in stage_count.items(): p = plan.get(stage) if p: total = p['amount_g_per_plant'] * count advice.append({ 'stage': stage, 'plant_count': count, 'action': p['action'], 'n_ratio': p['n_ratio'], 'p_ratio': p['p_ratio'], 'k_ratio': p['k_ratio'], 'amount_per_plant_g': p['amount_g_per_plant'], 'total_amount_g': total, 'note': p['note'] }) return advice # 示例:处理单张图片的推理结果 img_path = 'field_images/plot_001.jpg' txt_path = 'runs/predict/field_v1/labels/plot_001.txt' img = cv2.imread(img_path) h, w = img.shape[:2] dets = parse_yolo_txt(txt_path, w, h) advice = generate_fertilizer_advice(dets, FERTILIZER_PLAN) for a in advice: print(f"阶段: {a['stage']}, 株数: {a['plant_count']}, " f"措施: {a['action']}, 单株用量: {a['amount_per_plant_g']}g, " f"总用量: {a['total_amount_g']}g")

这段代码的逻辑是:读取 YOLOv11 保存的 txt 结果,还原检测框,按类别统计株数,再查施肥决策表,输出每个阶段的施肥建议。parse_yolo_txt里注意 YOLO 格式是归一化中心坐标,要乘回图像宽高。generate_fertilizer_advice按阶段汇总,方便种植户按区块施肥。

实际部署时,可以把这段逻辑封装成 API,接收图片返回 JSON 建议。也可以和温室控制系统对接,自动生成施肥工单。

3.3 推理结果保存与可视化:方便复查和调参

save=True和save_txt=True是基本操作,但我建议再加一个可视化脚本,把检测框和阶段标签画在图上,方便和种植户一起复查:

import cv2 def draw_detections(img_path, detections, output_path): img = cv2.imread(img_path) colors = { 'seedling': (0, 255, 0), 'vegetative': (255, 255, 0), 'flowering': (255, 0, 255), 'fruiting': (0, 165, 255), 'maturity': (0, 0, 255) } for det in detections: x1, y1, x2, y2 = det['bbox'] cls = det['class'] color = colors.get(cls, (255, 255, 255)) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, cls, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imwrite(output_path, img) draw_detections(img_path, dets, 'runs/predict/field_v1/vis_plot_001.jpg')

可视化不是花架子。田间复查时,种植户一眼就能看出模型把哪株认错了,这些反馈是下一轮迭代最值钱的数据。我习惯把误检和漏检的图单独存一个文件夹,标注后加入训练集,迭代两三轮后 mAP 通常能涨 5 到 10 个点。

4. 避坑与排查:作物生长阶段识别项目里最容易翻车的五件事

4.1 现象:模型在验证集上 mAP 很高,一到田间就乱框

原因:验证集和训练集来自同一批照片,光照、角度、背景高度相似,模型学到了背景捷径而不是作物特征。比如训练集全是顺光拍摄,模型可能把“亮绿色”当作苗期特征,遇到逆光就失效。

解决:数据划分时按拍摄日期或地块划分,不要随机打乱。训练集和验证集的光照条件要有差异。另外,在data.yaml里开启augment=True,用 HSV 抖动、随机翻转、随机裁剪增强泛化。如果田间误检严重,把conf从 0.15 提到 0.25,先保证准确率。

4.2 现象:开花期和坐果期总是分不清,混淆矩阵里两类互相错

原因:这两个阶段在视觉上确实接近,尤其是花谢后刚坐果的过渡期,花瓣残留和幼果同时存在。标注时不同人标准不一致,有人把带残花的标成开花期,有人标成坐果期。

解决:先统一标注规范,写清楚“花瓣脱落超过 50% 即算坐果期”。然后在训练时增加这两个类别的样本量,或者引入多标签分类,允许一株同时有开花和坐果标签。如果还是分不清,考虑加一个“过渡期”类别,把模糊样本单独归进去,施肥决策上按开花期处理。

4.3 现象:Jetson Nano 上推理一张图要 2 秒以上,达不到实时

原因:Jetson Nano 算力有限,YOLOv11m 直接跑 FP32 推理确实吃力。另外,如果输入分辨率是 1280,耗时会更长。

解决:导出 TensorRT 引擎,用 FP16 或 INT8 量化。命令如下:

yolo export model=runs/crop_stage/exp_v1/weights/best.pt format=engine half=True device=0

导出后在 Jetson 上用trtexec或 Ultralytics 的YOLO('best.engine')加载。实测 YOLOv11n 在 Jetson Nano 上 FP16 推理 640 分辨率可以到 8 到 12 FPS,够用。如果还慢,把模型换成 yolo11n.pt 重新训练,精度损失通常 2 到 3 个点,但速度翻倍。

4.4 现象:施肥建议里株数统计忽多忽少,同一张图两次推理结果不一致

原因:推理时conf阈值附近的目标不稳定,置信度 0.14 和 0.16 之间波动,导致有时框有时不框。另外,如果图片有压缩伪影,也会影响检测。

解决:固定推理参数,不要每次手动改。在决策模块里加一个“最小株数阈值”,比如某阶段检测到少于 3 株时,提示人工复核,不自动出施肥建议。还可以对同一张图做 TTA(测试时增强),把原图、翻转图、缩放图的检测结果融合,稳定输出。

4.5 现象:模型只认训练过的品种,换一个番茄品种就认不准

原因:不同品种的叶片形状、颜色、株型差异很大,模型过拟合到了训练品种的纹理特征。

解决:如果项目覆盖多品种,训练时要混入各品种样本,每个品种至少 200 个实例。如果暂时只有单品种数据,可以在推理时加一个品种选择开关,不同品种加载不同的决策表和置信度阈值。长期来看,收集多品种数据做增量训练是唯一出路。我一般建议每季作物结束后,把新数据标注后加入训练集,滚动迭代。

5. 进阶技巧:用阶段时序平滑和置信度加权把施肥决策做稳

单张图片的检测结果难免有抖动,但作物生长阶段在时间上是连续的,不会一株番茄今天开花明天就坐果。利用这个时序先验,可以把决策做稳。我常用的方法是:对同一地块连续多天的推理结果做滑动窗口投票,窗口大小 3 到 5 天,取众数作为当前阶段。如果某天检测结果和前后两天差异过大,标记为异常,人工复核。

具体实现上,可以建一个简单的 SQLite 表,每天存一次各地块的阶段统计:

import sqlite3 from datetime import datetime, timedelta def smooth_stage(plot_id, current_stage, db_path='farm.db'): conn = sqlite3.connect(db_path) c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS stage_log (plot_id TEXT, date TEXT, stage TEXT, count INTEGER)''') today = datetime.now().strftime('%Y-%m-%d') c.execute('INSERT INTO stage_log VALUES (?, ?, ?, ?)', (plot_id, today, current_stage, 1)) # 取最近5天记录 five_days_ago = (datetime.now() - timedelta(days=5)).strftime('%Y-%m-%d') c.execute('''SELECT stage, SUM(count) FROM stage_log WHERE plot_id=? AND date>=? GROUP BY stage ORDER BY SUM(count) DESC''', (plot_id, five_days_ago)) rows = c.fetchall() conn.commit() conn.close() if not rows: return current_stage # 众数阶段 smoothed = rows[0][0] # 如果当前阶段和众数差异大,记录异常 if current_stage != smoothed: print(f"警告:地块{plot_id}当前检测为{current_stage}," f"近5天众数为{smoothed},建议复核") return smoothed

这段代码的逻辑是:每次推理后把阶段写入数据库,查询最近 5 天的阶段分布,取出现次数最多的作为平滑结果。如果当天结果和平滑结果不一致,输出警告。这样能有效过滤单日误检,避免因为一张图的误判就多施一次肥。

另一个技巧是置信度加权。YOLOv11 输出的每个检测框都有置信度,统计株数时不要简单计数,而是把置信度作为权重。比如检测到 10 株开花期,平均置信度 0.9,和检测到 10 株平均置信度 0.5,前者更可信。可以在决策模块里设一个“有效株数”阈值,置信度低于 0.3 的检测框不计入统计,0.3 到 0.6 的按 0.5 株计,高于 0.6 的按 1 株计。这样施肥建议会更保守,减少误判带来的过量施肥风险。

最后说一个我自己的习惯:每次模型迭代后,不要只看 mAP,一定要把新模型和老模型在同一批田间图上跑一遍,对比施肥建议的差异。如果新模型让某地块的施肥量突然翻倍,先别高兴,大概率是误检多了。我一般会保留一个“保守版”模型和一个“激进版”模型,保守版conf高、只报高置信度目标,激进版conf低、尽量不漏检。实际施肥决策用保守版,巡检排查用激进版。这套双模型策略帮我省了好几次后悔药。

希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询