YOLOv11果实识别与路径规划:从检测到轨迹的闭环系统设计
发布时间:2026/9/30 8:38:16来源:尧图网络
简介这份PDF文档面向农业机械自动化、计算机视觉方向的学习者与研究人员围绕YOLOv11在收割机果实识别与路径规划中的系统设计展开帮助读者理解目标检测算法如何落地于智能农机场景。文档共33页以单个PDF文件形式打包压缩包约1.9MB支持目录章节跳转、阅读器左侧大纲显示与章节快速定位查阅体验完整流畅。内容从农业机械自动化背景与YOLOv11技术原理讲起依次覆盖图像采集与预处理、果实识别模型训练与后处理、环境建模与路径规划算法、系统集成与硬件平台搭建并给出实验结果对比与性能评估目录结构层次分明。目前已有51人学习下载适合希望系统掌握YOLOv11工程实践、借鉴完整项目设计思路的读者参考文档仅供学习使用。1. 收割机装上一双会认果子的眼睛YOLOv11 果实识别与路径规划到底在解决什么去年秋天我在一个柑橘合作社的采收季蹲了三天最直观的感受是收割机驾驶员一天要踩上千次刹车不是因为机械故障而是因为垄间突然出现的落果、歪斜的树冠和临时堆放的果筐。农业机械自动化喊了很多年真正卡住落地的一直不是机械臂的力气而是看见和绕开这两件事。YOLOv11 果实识别与路径规划系统设计讲的就是把目标检测和路径规划串成一条闭环摄像头或工业相机采集垄间图像YOLOv11 负责把成熟果实、未熟果实、枝叶遮挡和地面落果区分出来再把检测框的中心点投影成田间坐标系里的障碍物或目标点最后交给路径规划模块生成一条能走、能收、能避的行驶轨迹。这套方案适合做农机改造的嵌入式工程师、做农业机器人的算法同学以及想从零搭一台采收原型机的团队。它不追求实验室里的 mAP 刷榜追求的是在颠簸、逆光、扬尘和果实重叠的真实果园里机器还能稳定地把果子认出来、把路走对。2. YOLOv11 果实识别从数据标注到模型选型的落地链路2.1 为什么是 YOLOv11而不是 Faster R-CNN 或 YOLOv8果园场景对检测模型的要求很具体帧率要够因为收割机行进速度虽然只有 0.51.5 m/s但相机要连续出图给规划模块模型要小因为算力平台通常是 Jetson 系列或 RK3588 这类嵌入式板卡对小目标和遮挡目标要稳因为果实经常被叶片挡掉三分之一。YOLOv11 相比前代在 neck 部分做了结构精简参数量和延迟都有下降同时保留了多尺度特征融合这对识别直径只有几十像素的小果实很关键。Faster R-CNN 这类两阶段检测器精度不差但推理延迟在嵌入式平台上很难压到 30 ms 以内规划模块等不起。YOLOv8 也能用但如果你要做剪枝、量化和 TensorRT 部署YOLOv11 的导出链路更顺社区里 yolov11 部署和 yolov11 环境配置的资料也足够多踩坑成本低。选型时我一般会先确认三件事相机分辨率和安装高度决定果实像素尺寸果实像素尺寸决定输入分辨率输入分辨率决定模型能不能在目标板卡上跑满帧。常见做法是 1280×720 采集模型输入 640×640果实像素在 2080 之间这个区间 YOLOv11n 或 YOLOv11s 都能覆盖。2.2 果实数据集标注四个类别和三条标注规则农业果实识别不需要几百个类别但类别划分要贴合采收决策。我一般会分成四类成熟果实、未熟果实、遮挡果实、地面落果。成熟果实是采收目标未熟果实是看见但不摘遮挡果实用于判断是否值得机械臂伸过去地面落果是障碍物。标注规则有三条血泪经验第一遮挡超过 70% 的果实不标否则模型会学到一堆模糊特征第二相邻果实紧贴时标注框不要重叠超过 20%不然后处理 NMS 会把两个果子合并成一个第三逆光和高光区域的果实要单独补采否则模型在上午十点和下午三点的表现会差出一大截。标注工具用 LabelImg 或 CVAT 都行导出 YOLO 格式。目录结构按下面组织后面训练脚本直接读这个结构fruit_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml里写清路径和类别名nc是类别数names顺序必须和标注时的类别索引一致否则训练出来的模型会把成熟果实认成落果。path: ./fruit_dataset train: images/train val: images/val test: images/test nc: 4 names: [ripe, unripe, occluded, fallen]2.3 训练命令与关键参数把 mAP 和延迟一起看环境配置这块我一般用 Python 3.10 PyTorch 2.1 CUDA 12.1YOLOv11 的依赖装完后先跑一次官方预训练权重推理确认环境没问题再上自己的数据。训练命令如下yolo detect train \ modelyolo11s.pt \ datafruit_dataset/data.yaml \ epochs200 \ imgsz640 \ batch16 \ device0 \ workers8 \ patience30 \ lr00.01 \ lrf0.01 \ mosaic1.0 \ mixup0.1 \ degrees15 \ translate0.1 \ scale0.5 \ fliplr0.5 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4epochs200配合patience30验证集 mAP 连续 30 轮不涨就早停避免过拟合。imgsz640是精度和速度的平衡点如果你用 Jetson Nano 这类算力有限的板子可以降到 416 或 320但小果实召回会掉。mosaic1.0和mixup0.1是数据增强果园场景里果实重叠多mosaic 能显著提升遮挡情况下的鲁棒性。degrees15和scale0.5模拟相机安装角度偏差和果实远近变化。hsv_h/s/v三组参数针对光照变化果园里树荫和阳光交替出现这三组不调的话模型在阴影区基本失效。训练完看两个指标mAP50-95 和单帧推理延迟。mAP 高但延迟超过 50 ms 的模型规划模块会抖实际采收效率反而低。我一般要求 mAP50 在 0.85 以上TensorRT FP16 推理延迟在 25 ms 以内才算能上车。2.4 推理结果保存与部署前验证训练完先别急着部署用yolo detect predict把验证集跑一遍保存推理结果图肉眼检查漏检和误检。命令里save_txtTrue会把检测框坐标存成 txt后面做路径规划时直接读这些坐标不用再跑一次模型。yolo detect predict \ modelruns/detect/train/weights/best.pt \ sourcefruit_dataset/images/val \ imgsz640 \ conf0.35 \ iou0.45 \ saveTrue \ save_txtTrue \ save_confTrue \ projectruns/predict \ namefruit_valconf0.35是置信度阈值果园场景里我一般设得比通用检测低一点因为果实被遮挡时置信度会掉设太高会漏掉可采收的果子。iou0.45控制 NMS 重叠阈值果实紧贴时这个值要调低到 0.4 左右否则两个果子会被合并。save_confTrue保存置信度路径规划时可以根据置信度决定是否靠近低置信度目标可以只做避障不做采收。部署到 Jetson 平台时常见做法是先把 PyTorch 权重导出成 ONNX再用 TensorRT 做 FP16 或 INT8 量化。导出命令yolo export modelbest.pt formatonnx opset12 simplifyTrueopset12兼容性最好simplifyTrue会做图优化去掉冗余算子。导出后在 Jetson 上用trtexec转 engineINT8 量化需要校准集一般从验证集里抽 200500 张图做校准。量化后 mAP 掉 12 个点是正常的如果掉超过 5 个点检查校准集是否覆盖了逆光和遮挡场景。3. 从检测框到行驶轨迹路径规划模块怎么接 YOLOv11 的输出3.1 检测结果转障碍物地图坐标系变换的三个步骤YOLOv11 输出的是图像像素坐标路径规划需要的是田间平面坐标。中间要做三步变换像素坐标转相机坐标、相机坐标转田间坐标、田间坐标栅格化。第一步用相机内参矩阵第二步用相机外参安装高度、俯仰角、偏航角第三步按规划分辨率把田间划分成栅格每个栅格标记占用、空闲或目标。相机标定用棋盘格做一次就行内参矩阵和畸变系数存成 yaml。外参在安装时测量俯仰角误差超过 2 度投影到地面的果实位置就会偏出 10 cm 以上机械臂会抓空。我一般会在田间放几个已知坐标的标记物反算外参做校验。import numpy as np import cv2 # 相机内参和畸变系数标定一次即可 K np.array([[615.2, 0, 320.1], [0, 615.8, 240.3], [0, 0, 1]]) dist np.array([-0.12, 0.05, 0.001, -0.002, 0.0]) # 相机外参安装高度 1.2m俯仰角 30 度 h 1.2 pitch np.deg2rad(30) R np.array([[1, 0, 0], [0, np.cos(pitch), -np.sin(pitch)], [0, np.sin(pitch), np.cos(pitch)]]) t np.array([0, 0, h]) def pixel_to_field(u, v): # 去畸变 pts np.array([[[u, v]]], dtypenp.float32) undist cv2.undistortPoints(pts, K, dist, PK) uu, vv undist[0][0] # 归一化相机坐标 x_c (uu - K[0, 2]) / K[0, 0] y_c (vv - K[1, 2]) / K[1, 1] # 相机坐标转田间坐标假设地面 z0 vec np.array([x_c, y_c, 1.0]) vec R.T vec scale -t[2] / vec[2] p_field t scale * vec return p_field[0], p_field[1]这段代码的核心是pixel_to_field函数输入检测框底部中心点输出田间平面坐标。R.T vec把相机坐标系下的射线转到田间坐标系scale -t[2] / vec[2]求射线与地面交点。注意检测框底部中心点比框中心点更接近果实与地面的接触点用底部中心做投影机械臂抓取时高度误差更小。3.2 栅格地图与改进 A*让路径贴着垄走田间路径规划和室内导航不一样垄间通道窄果实分布有规律路径不能随便斜穿。我一般用栅格地图 改进 A*在代价函数里加两个约束一是靠近垄线有低代价偏离垄线代价升高二是靠近成熟果实有额外代价避免机械臂或车身碰掉果子。栅格分辨率取 5 cm 比较合适太小计算量大太大路径会蹭到树冠。改进 A* 的代价函数import heapq def heuristic(a, b): return abs(a[0] - b[0]) abs(a[1] - b[1]) def cost(node, neighbor, grid, ripe_points): base 1.0 # 垄线约束偏离垄线代价增加 lane_penalty 0.5 * abs(neighbor[1] - lane_center(neighbor[0])) # 果实避让靠近成熟果实代价增加 fruit_penalty 0.0 for fp in ripe_points: d ((neighbor[0] - fp[0])**2 (neighbor[1] - fp[1])**2)**0.5 if d 0.3: fruit_penalty 2.0 * (0.3 - d) # 障碍物直接不可通行 if grid[neighbor[0]][neighbor[1]] 1: return float(inf) return base lane_penalty fruit_penalty def astar(grid, start, goal, ripe_points): open_set [(0, start)] came_from {} g_score {start: 0} while open_set: _, current heapq.heappop(open_set) if current goal: path [] while current in came_from: path.append(current) current came_from[current] return path[::-1] for dx, dy in [(-1,0),(1,0),(0,-1),(0,1),(-1,-1),(-1,1),(1,-1),(1,1)]: neighbor (current[0]dx, current[1]dy) if not (0 neighbor[0] len(grid) and 0 neighbor[1] len(grid[0])): continue tentative g_score[current] cost(current, neighbor, grid, ripe_points) if tentative g_score.get(neighbor, float(inf)): came_from[neighbor] current g_score[neighbor] tentative f tentative heuristic(neighbor, goal) heapq.heappush(open_set, (f, neighbor)) return Nonelane_penalty让路径尽量贴着垄线走fruit_penalty让路径和成熟果实保持 30 cm 以上距离。grid里 1 表示障碍物0 表示可通行障碍物来自 YOLOv11 检测到的地面落果和树干。八邻域搜索比四邻域路径更平滑但计算量稍大实际跑下来 100×100 的栅格在 Jetson 上单次规划 10 ms 以内够用。3.3 动态避障检测帧间抖动怎么处理YOLOv11 逐帧检测会有抖动同一颗果实在相邻帧的检测框可能差几个像素投影到田间坐标后可能差几厘米。如果每帧都重新规划路径会来回摆。我一般做两层滤波第一层对检测框做卡尔曼滤波平滑中心点轨迹第二层对栅格地图做衰减更新新检测到的障碍物立即标记连续 5 帧没检测到的障碍物才清除。卡尔曼滤波用 OpenCV 的KalmanFilter就行状态向量取[x, y, vx, vy]观测向量取[x, y]。果实静止时vx, vy接近 0滤波后中心点抖动可以压到 12 像素。栅格衰减用一个计数器每个栅格记录被检测到的帧数超过阈值才置为障碍物低于阈值逐渐降级。动态避障小车路径规划里常用的 DWA 也可以接在 A* 后面做局部避障但果园场景速度低A* 加滤波已经够稳。如果收割机速度超过 1.5 m/s建议加一层 DWA 做局部速度采样避免急停。4. 避坑与排查果园实测里最容易翻车的五个点4.1 逆光下果实全黑模型漏检率飙升现象上午十点和下午三点相机对着太阳方向拍成熟果实变成黑色剪影YOLOv11 漏检超过 40%。原因训练集里逆光样本太少模型没学到剪影特征另外相机自动曝光在逆光时会把整体亮度压低果实和背景对比度消失。解决补采逆光样本至少占训练集 15%相机开 HDR 或手动曝光锁定曝光值避免逐帧跳变训练时把hsv_v调高到 0.5增强亮度扰动。4.2 果实紧贴时 NMS 合并两颗果子只出一个框现象两根枝条交叉处的果实检测结果只有一个框机械臂只摘一颗另一颗漏掉。原因iou阈值设太高NMS 把重叠框合并了或者标注时两个果实框重叠超过 20%模型学到的特征本身就混在一起。解决推理时iou降到 0.4标注时紧贴果实框重叠控制在 20% 以内后处理加一个基于颜色的分割把合并框按颜色直方图拆开。4.3 路径规划贴树太近车身刮掉未熟果实现象A* 路径为了最短贴着树冠走车身蹭掉未熟果实造成减产。原因代价函数只考虑了障碍物和成熟果实没有把未熟果实和树冠纳入代价。解决把未熟果实和树冠也投影到栅格地图设置膨胀半径 2030 cmlane_penalty权重调高让路径优先走垄间中心。4.4 Jetson 上 TensorRT 量化后 mAP 掉太多现象PyTorch 模型 mAP50 0.88转 TensorRT INT8 后掉到 0.72。原因校准集只用了晴天样本没有覆盖逆光、阴影和遮挡场景量化时敏感层被强制 INT8。解决校准集从验证集里分层抽样覆盖各种光照和遮挡用trtexec的--layerPrecisions把检测头最后几层保持 FP16量化后重新跑验证集掉点超过 3 个就回退 FP16。4.5 相机外参漂移果实投影位置偏出 10 cm现象机器跑了一上午下午抓取时机械臂总是偏左或偏右。原因相机支架在颠簸中松动俯仰角变了 12 度或者田间地面不平相机高度变化。解决相机支架加防松垫片每天开工前用田间标记物校验外参如果地面起伏大加 IMU 做姿态补偿实时修正俯仰角。5. 把识别和规划串成闭环一个可复现的验证技巧整套系统跑通后别急着下地。我一般会在试验田里做一次影子模式验证机器正常行驶YOLOv11 和路径规划都跑但规划结果不发给执行机构只记录检测框、投影坐标、规划路径和实际行驶轨迹。跑完一圈把记录导出来对比规划路径和实际轨迹的偏差以及检测框和人工标注的差异。这个技巧能提前暴露 80% 的集成问题比如坐标系对不上、时间戳不同步、滤波参数太激进。验证脚本的核心是记录每一帧的时间戳、检测结果和规划路径存成 CSVimport csv import time def log_frame(frame_id, detections, path, actual_pose): with open(shadow_log.csv, a, newline) as f: writer csv.writer(f) writer.writerow([ frame_id, time.time(), len(detections), ;.join([f{d[0]:.2f},{d[1]:.2f},{d[2]:.2f} for d in detections]), ;.join([f{p[0]},{p[1]} for p in path]) if path else , f{actual_pose[0]:.3f},{actual_pose[1]:.3f},{actual_pose[2]:.3f} ])detections存的是田间坐标下的果实位置和置信度path是规划路径点actual_pose是实际位姿。跑完后用 pandas 读 CSV算规划路径和实际轨迹的 Hausdorff 距离超过 15 cm 的帧标出来人工看。检测部分把detections和人工标注对比算漏检和误检。参数上我一般要求规划路径和实际轨迹偏差在 10 cm 以内检测漏检率低于 5%误检率低于 3%。达不到就回去调滤波参数、外参或 NMS 阈值。这个验证跑两三轮系统基本就能稳定下地了。我自己踩过最大的坑是跳过影子模式直接下地结果机器在田里画龙一上午刮掉几十颗果子。后来老老实实做影子验证把坐标系和时间戳对齐问题才收敛。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网