简介:计算机视觉在果蔬机械采摘中的应用研究是一份PDF格式的学术参考文献,面向农业自动化、智能采摘及计算机视觉方向的研究人员与在校学生。资源针对传统人工采摘劳动强度大、目标识别困难等问题,系统讲解计算机视觉系统的工作原理,包括成像装置与计算机两大部分、照明装置的作用以及单色/彩色摄像机的选型;随后构建双目立体视觉数学模型,给出利用视差计算目标深度的定位公式,并介绍机械采摘系统硬件组成与软件流程。全文源自期刊论文,配有系统工作原理图和视觉模型示意图,结构严谨,适合作为课题研究、课程设计或论文写作的专业指导。压缩包仅含1个PDF文件,大小1.35MB,已有91人浏览学习。读者可从中掌握从成像装置配置、图像处理与特征提取、双目视差计算到机械臂执行控制联动的完整技术链条,为优化果蔬采摘系统的识别精度和鲁棒性提供直接参考。
1. 果蔬采摘不是“换个场景跑模型”:为什么视觉方案卡在果园而不是测试集
计算机视觉在果蔬机械采摘里的地位,比很多人想象的要重。采摘机器人的机械臂和末端执行器这些年已经做得比较成熟,真正决定“能不能摘下来”的,往往是视觉系统给出的目标位置和成熟度判断准不准。我在这类项目里见过最多的翻车现场是:检测模型在测试集上 mAP 高得漂亮,一装到果园平台车上,遇上逆光、枝叶晃动和果实互相遮挡,框就开始乱跳,机械臂跟着空抓。这类以 PDF 形式流传的研究资料,拆开来看,讲的不是某一个模型的调参记录,而是从图像采集、目标识别、三维定位到机械臂引导的一整套工程链路。如果你正处在计算机视觉入门的阶段,或者做完课程项目想往农业现场迁移,这份拆解能帮你少走不少弯路。它适合采摘机器人方向的工程师,也适合打算把实验室视觉方案搬去果园的团队。
2. 果蔬采摘视觉系统要解决的三件事:识别、定位与成熟度判断
2.1 采摘场景与工业质检场景的差异:目标会动、光线会变、枝条会挡
工业视觉质检的场景通常是:零件固定、光源固定、相机位置固定,视觉系统要做的就是在恒定条件下找缺陷。果蔬采摘完全是另一个极端:果实长在树上,姿态随机,枝叶遮挡比例可能达到 20%,阳光角度从早上到下午能变六十度。计算机视觉和机器学习区别在这类项目里体现得最明显——目标检测和成熟度判断依赖机器学习模型,而相机标定、坐标变换、手眼关系这一类是纯几何问题,模型再强也没法替代标定。
这带来三个直接后果。第一,检测模型不能只学“完整果实”的模板,必须对截断和遮挡鲁棒,否则遮了一半的果实直接漏检。第二,机械臂要的是一个三维抓取点,2D 检测框本身不够用,还需要深度信息或额外的几何计算。第三,成熟度判断不能简单看 RGB 像素均值,因为同样的苹果在正午阳光和傍晚树荫下,RGB 值可能差出一大截。
如果你刚走完一版计算机视觉学习路线,照着 CS231N 公开课里的 PPT 把目标检测、图像分类刷了一遍,很容易掉进“模型精度第一”的思维定式。课程大作业教的是在标准数据集上刷分,果园里却没有现成数据集,只有一台相机和一片你控制不了光照的树。所以采摘视觉的第一步不是调模型,而是选好相机、定好拍摄策略、把数据闭环建立起来。想明白这件事,后面所有环节的推进都会顺很多。
2.2 成熟度判断:颜色空间直方图与深度学习回归怎么选
成熟度判断在论文里会有各种高光谱、遥感指数的方法,但真正落地时主流只有两条路线:传统颜色阈值和深度学习分类/回归。
传统颜色阈值常用 HSV 空间而不是 RGB。原因很简单:HSV 把亮度放在独立的 V 通道,色调 H 和饱和度 S 对光照变化相对不敏感。对番茄、柑橘这类成熟后果色变化明显的果实,设定“色调在某个区间、饱和度高于某个下限”就能把可采果和青果分开。这个方法没有标注成本,算力几乎为零,适合作为第一版基线。
深度学习方法则把成熟度当成一个分类或回归任务。常见做法是训练一个小型 CNN,输入果实区域图像,输出 1~5 的成熟度等级,或者直接回归一个 0~1 的成熟度分数。它的优势是能处理颜色不规律的品种,例如有些苹果成熟后仍带青底,单靠色调阈值会误判。代价是需要对每颗果实做成熟度标注,标注一致性还很难保证。下表是我常用的选型对比:
| 方法 | 光照鲁棒性 | 标注成本 | 算力需求 | 适用场景 |
|---|---|---|---|---|
| HSV 色调阈值 | 中 | 无 | 极低 | 番茄、柑橘、红苹果等颜色分级清晰的果实 |
| 色差指数(Lab 空间) | 中 | 无 | 极低 | 需要连续量化颜色指标时 |
| CNN 成熟度分类 | 较高 | 高 | 中 | 颜色不规律、遮挡多的露天环境 |
| 高光谱成像 | 高 | 很高 | 高 | 温室或设施农业,光照可控 |
我在实际项目里的顺序是:先用 HSV 规则跑半个月现场视频,统计误判率,如果超过 10% 再考虑训练成熟度分类器。采摘系统的核心诉求是“可采/不可采”的决策稳,而不是成熟度等级分得有多细。很多论文把成熟度切成五级,但机械臂只需要知道现在能不能摘。
2.3 相机选型:2D、双目、结构光与 ToF 的取舍
既然机械臂要三维坐标,单颗 2D 相机就满足不了要求。常见的深度获取方式有四种:2D RGB、双目立体视觉、结构光、ToF 飞行时间。表面上看都能给坐标,实际田间表现差别很大。
| 方案 | 深度原理 | 露天抗光性 | 典型精度 | 主要坑 |
|---|---|---|---|---|
| 2D RGB | 无,需另算深度 | 一般 | 像素级 | 没有深度,必须搭配其他方案 |
| 双目 | 左右视差匹配 | 中 | mm 到 cm | 弱纹理区域视差空洞 |
| 结构光 | 投射编码光斑 | 差 | mm 级 | 阳光直射下光斑失效 |
| ToF | 光飞行时间 | 较好 | cm 级 | 边缘飞点、多径干扰 |
结构光相机在室内精度很高,但露天果园里阳光直射时编码光斑直接被环境光淹没,基本不可用。双目相机在近距离效果不错,问题是果树枝叶表面纹理太碎,视差图里经常出现一块块空洞,果实边缘的深度值不稳定。ToF 在阳光下相对能扛,但深度边缘的飞点很麻烦,果实和叶子交界处的深度会突然跳变。
我一般推荐“一台彩色相机 + 一台 ToF 或双目”的组合:彩色图负责检测和成熟度,深度图负责定位。两个相机先做外参标定,把彩色图上的检测框中心映射到深度图坐标系上,然后在深度图上取中心邻域的深度中值,作为抓取深度。这个方案比纯双目多了一个标定环节,但每一路的算法都能做到简单稳定,后期排障也容易。
如果想省掉外参标定,也可以直接用高质量双目相机,在左目图上做检测,再通过视差图找深度。这几年边缘算力提升后这种方案开始可行,只是在反光叶片多的果园里,双目视差空洞的问题仍然存在。选型取舍可以按“先求稳、再求集成度”来定:第一版系统里模块越独立越好,别把深度和检测耦合在同一个算法里。
3. 用 YOLOv8 在本地跑通果蔬检测:数据集、训练、导出与成熟度规则
3.1 果蔬数据集准备:实拍数量、YOLO 标注格式与增强
采摘数据集和公开数据集最大的差别是背景复杂度和目标姿态。COCO 里也有水果,但大多是货架商品图或者摆拍图,背景干净、光线均匀、目标完整。果园实拍图的背景是枝条、叶子、天空和地面,果实之间互相遮挡,颜色还随环境强烈变化。所以第一原则是:训练数据必须尽量来自目标果园现场,不能用公开图凑数。
我一般每个果实类别准备 800~1500 张实拍图,覆盖阴天、晴天、上午、下午四种条件,物候期至少两个阶段,比如青果期和转色期。图像保留相机原始分辨率,训练时统一缩放到 640。标注格式用 YOLO 文本格式,每行一条目标:
<类别ID> <中心x/图宽> <中心y/图高> <目标宽/图宽> <目标高/图高>坐标全部归一化到 0~1 之间。标注工具用 LabelImg 或 X-AnyLabeling 这类带 YOLO 导出的工具就行,重点是把“枝条”也标成一个类别。
注意:如果数据集里没有枝条类别,强烈建议在标注阶段就补上。机械臂避障需要它,现在不标,后面补标的时间和沟通成本高好几倍。
数据增强里值得做的依次是:亮度对比度扰动、随机旋转±30°、随机裁剪、马赛克增强。不建议做的是水平翻转和垂直翻转。果子有上垂下挂的天然姿态,翻转后模型学到的是在图像里“倒挂的果子”,定位和姿态后续都会出问题。YOLO 训练时自动增强默认开着,通常够用,别再叠加一层随机翻转。
3.2 训练命令和关键参数:epochs、imgsz、batch、patience 怎么给
先给一个最小配置文件。项目根目录下建一个agri.yaml:
# agri.yaml path: ./datasets/agri train: images/train val: images/val nc: 2 names: 0: apple 1: branch训练命令我一般这样写,在 PyCharm 或 VS Code 的终端里直接跑:
# 在独立虚拟环境里执行,Python 3.10 以上即可 yolo detect train \ data=config/agri.yaml \ model=yolov8n.pt \ epochs=120 \ imgsz=640 \ batch=16 \ patience=15 \ project=./runs \ name=apple_v1几个关键参数值得单独说明。model 选择yolov8n.pt是因为采摘机器人边缘设备的算力有限,n 版最快;如果设备是 Jetson Orin 这类,可以换yolov8s.pt或yolov8m.pt,m 版在遮挡场景的召回率明显更好。没有把握时先用 n 跑通全流程,再往大模型迁移。
imgsz 设 640 是精度和速度的平衡点。设 416 对小目标召回差,设 1280 虽然精度更高但算力需求翻好几倍,边缘设备很难实时。batch 看显存,16 不行就降到 8,batch 对最终精度的贡献远不如 imgsz 和模型尺寸明显。
patience 设 15,意思是验证集指标连续 15 个 epoch 不涨就早停。采摘数据分布杂,这个值太大会让训练拖到过拟合,太小又可能没跑到位就停了。跑完后看runs/apple_v1/weights/下的best.pt,它是对验证集最优的权重。
3.3 推理脚本:检测框叠加成熟度评分
模型训好之后,一个比较完整的推理脚本长这样。它同时输出检测框和成熟度评分:
from ultralytics import YOLO import cv2 import numpy as np model = YOLO("runs/apple_v1/weights/best.pt") img_bgr = cv2.imread("test_frame.jpg") img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) results = model.predict(img_rgb, conf=0.45, imgsz=640, verbose=False) def estimate_maturity(crop_rgb): """用色调和饱和度粗判成熟度,返回 0~1 分数。""" hsv = cv2.cvtColor(crop_rgb, cv2.COLOR_RGB2HSV) sat_mask = hsv[:, :, 1] > 60 # 只统计有颜色信息的像素 hue = hsv[:, :, 0][sat_mask] if len(hue) == 0: return 0.0 # 红色果实的色调集中在 0 附近,用高斯曲线把距离转为分数 red_score = np.mean(np.exp(-((hue - 5.0) / 20.0) ** 2)) return float(red_score) for r in results: for box in r.boxes: cls = int(box.cls[0]) if model.names[cls] != "apple": continue x1, y1, x2, y2 = map(int, box.xyxy[0].tolist()) crop = img_rgb[y1:y2, x1:x2] score = estimate_maturity(crop) print(f"框=({x1},{y1})-({x2},{y2}) 成熟度={score:.2f}")这里用 HSV 而不是 RGB 判成熟度,是因为 HSV 把亮度剥离开了。拍摄角度和阴影变化主要影响亮度通道,色调相对稳定。hue - 5.0的基准针对红色果实,换成柑橘类要把基准调到 15 附近,或者先用一小段验证集统计色调分布再定。
3.4 导出 ONNX 并接入采摘控制程序
训练完成后,把权重导出成 ONNX,后续不管是 Python 还是 C++ 控制程序都能加载同一个模型文件:
yolo export model=runs/apple_v1/weights/best.pt format=onnx imgsz=640 opset=12导出后拿 ONNX Runtime 做一个最小推理:
import onnxruntime as ort import numpy as np import cv2 sess = ort.InferenceSession("best.onnx", providers=["CPUExecutionProvider"]) input_name = sess.get_inputs()[0].name def preprocess(img_bgr): img = cv2.resize(img_bgr, (640, 640)) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = img.astype(np.float32) / 255.0 img = img.transpose(2, 0, 1) return np.expand_dims(img, 0).astype(np.float32) def postprocess(output): # YOLOv8 输出形状 [1, 4+nc, 8400] preds = output[0] boxes = preds[:4].T # 中心点格式 scores = preds[4:].T.max(axis=1) cls_ids = preds[4:].T.argmax(axis=1) keep = scores > 0.45 return boxes[keep], scores[keep], cls_ids[keep]ONNX 导出的后处理最容易被漏掉。YOLOv8 的输出不是直接可用的框坐标,而是 8400 个候选目标的中心点、宽高和各类别分数,需要自己做阈值过滤。opset 设 12 兼容性比较好,部署到老版本 OpenCV 或者工业相机配套的 SDK 环境时不容易报错。在采摘控制程序里,检测线程和机械臂控制线程最好分开,检测结果放进共享队列,控制线程按最新一帧坐标执行,这样即使某帧检测慢了也不至于让机械臂停下等待。
4. 从像素坐标到机械臂抓取:手眼标定与坐标映射的完整走法
4.1 手眼标定选型:eye-in-hand 与 eye-to-hand 在果园里的取舍
手眼标定解决的是“相机看到的点”和“机械臂能抓的点”之间的关系。两种接法都有:eye-in-hand 是相机装在机械臂末端,跟着臂一起动;eye-to-hand 是相机固定在工作区域外,臂在相机视野里作业。
室内机器人常用 eye-in-hand,因为它可以靠近目标,精度高,而且机械臂运动时视野可以换。但果园里这套会吃亏:采摘平台在地里会颠簸,机械臂运动剧烈时末端相机图像模糊;线缆随着关节反复弯曲,故障率也高。eye-to-hand 把相机固定在采摘平台的支架上,视野覆盖整棵树的作业区域,一次标定能用很长时间。
我建议第一版采摘系统直接用 eye-to-hand,相机固定在平台上,标定一次后只要平台不换位置就不用重新标。平台移动后需要重新标定,所以整个标定流程必须能在田间快速重跑一遍。如果你走的是计算机视觉学习路线,可能更熟悉物体识别这一套,手眼标定的几何部分会显得枯燥,但它恰恰是采摘定位误差的主要来源。
4.2 用 OpenCV 标定相机内参:棋盘格拍摄与 calibrateCamera
内参标定是为了拿到相机的焦距、主点坐标和畸变系数。采摘现场的光线不可控,标定这一步不能省。用棋盘格照片标定的流程如下:
import cv2 import numpy as np # 棋盘格内角点数量,建议 9x6 objp = np.zeros((6 * 9, 3), np.float32) objp[:, :2] = np.mgrid[0:9, 0:6].T.reshape(-1, 2) * 25.0 # 25mm 一格 obj_points, img_points = [], [] calib_files = ["calib_01.jpg", "calib_02.jpg", ...] # 15~20 张 for f in calib_files: img = cv2.imread(f) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, corners = cv2.findChessboardCorners(gray, (9, 6), None) if ret: obj_points.append(objp) img_points.append(corners) ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera( obj_points, img_points, gray.shape[::-1], None, None ) print("内参矩阵:\n", mtx) print("畸变系数:\n", dist)拍摄经验就一条:15 到 20 张图必须覆盖整个视野,并且每张图的角度都不一样——有正对、有左倾、有右倾、有俯仰。全正对着拍是标不出来的,畸变参数会退化。果园现场光线强,棋盘格会反光,最好在树荫下标定,或者用哑光打印材料。标定后保存mtx和dist,后面每一步都用同一份内参,不要在多个环节各自重新标。
4.3 从 2D 检测框到三维抓取点:solvePnP 与齐次变换链
拿到内参之后,把像素坐标变成三维坐标有两种常见路径。如果目标有已知尺寸和姿态,比如果箱或者人工放好的标记物,可以用 solvePnP 直接求位姿。果实没有固定姿态,通常用深度图反投影更直接。
反投影代码:
import numpy as np # mtx 来自标定,depth_mm 是深度图在像素 (u,v) 处的深度值 def image_to_camera(u, v, depth_mm, mtx): fx = mtx[0, 0]; fy = mtx[1, 1] cx = mtx[0, 2]; cy = mtx[1, 2] x = (u - cx) * depth_mm / fx y = (v - cy) * depth_mm / fy z = depth_mm return np.array([x, y, z]) # 相机到机械臂基座的齐次变换矩阵,由手眼标定得到 T_base_cam = np.load("T_base_cam.npy") # shape (4, 4) def camera_to_base(p_cam): p = np.append(p_cam, 1.0) p_base = T_base_cam @ p return p_base[:3]这里有两处最容易踩。第一,深度值不要取单像素。ToF 和双目在果实边缘都有噪声,单点可能跳变好几厘米,常见做法是取检测框中心区域 5x5 邻域的深度中位数。第二,T_base_cam的平移单位必须和深度图一致,深度图是毫米,平移向量也得是毫米。
注意:深度图单位是毫米,手眼矩阵的平移向量也必须用毫米。米和毫米混用的结果是机械臂直接抓到空气里。
计算机视觉几何偏置在采摘定位里是绕不开的坎,矩阵里的符号、单位、行序错一个地方,末端位置就偏出好几厘米,而且这种错误很难在屏幕上用肉眼发现。
4.4 抓取目标点怎么定:果梗优先还是果心优先
检测框给的是果实的包围盒,中心点不一定适合抓。像苹果、梨这类有果梗的水果,抓果梗不容易损伤果体,但果梗在图像里细、短、容易被叶子挡住。番茄、柑橘则适合直接抓果心,只要末端夹爪力度控制好就行。
我一般会在检测框基础上单独找果梗:在框内图像上用边缘检测或一个小分割模型把果梗区域提出来,取它的质心作为抓取点。找不到果梗时再退回果心,这时候机械臂会多一个“保护性动作”,比如降低夹持力度或者先碰触再用力。前面在数据集里加branch类别,也是给这一步用的——抓取路径规划时,视觉系统同时把枝条障碍输给机械臂,避障路径会好做很多。如果只检测果实不管枝条,采摘过程中机械臂和枝条纠缠会是家常便饭。
如果论文方案里提到抓取姿态估计,说的是在坐标之外还给一个果梗朝向角。小场景下可以先省略,让机械臂沿着相机到果心的方向逼近,连续抓取成功率足够验证时,再引入姿态估计也不迟。
5. 果蔬采摘视觉系统的 5 个踩坑现场与排查方法
5.1 检测框一抖,机械臂就开始乱抓:NMS 阈值与目标平滑
现象:果实被风吹动时,同一颗果子的检测置信度在 0.45 左右来回跳,这一帧有框、下一帧没框,机械臂按瞬时坐标执行,抓空率明显提高。
原因:目标检测器本身是逐帧独立推理的,没有时序记忆。果实摆动、遮挡变化、快门模糊都会让置信度抖动。置信度阈值再低一点,就会在“有框”和“没框”之间反复横跳。
解决:把检测置信度阈值调到 0.6,然后对检测框中心做指数移动平均。下面这段可以用在任何检测后端上:
# 对检测框中心做 EMA 平滑,alpha 越大跟随越快 def smooth_center(prev_pt, new_pt, alpha=0.4): if prev_pt is None: return new_pt x = alpha * new_pt[0] + (1 - alpha) * prev_pt[0] y = alpha * new_pt[1] + (1 - alpha) * prev_pt[1] return (x, y)更完整的做法是接一个 IOU Tracker 或者 ByteTrack 之类的追踪器,给每个目标分配 ID,目标丢帧后在短暂生命周期内沿用上一帧位置。这样机械臂不需要每秒都拿到新坐标,也能保持连续动作。先平滑再追踪,顺序不要反。
5.2 大晴天果实过曝,检测框直接消失:曝光锁定与偏振片
现象:晴天下午的果园里,自动曝光模式下检测率骤降,向阳面的果实变成一片白色,图里几乎没有纹理。
原因:相机的自动曝光会被大面积天空和叶片带偏,局部过曝导致果实失去颜色和边缘信息。自动白平衡也会随着画面内容漂移,同一种果实早上和下午测出来的色调都不一样。
解决:手动固定曝光时间和 ISO,关闭自动曝光;白平衡也用手动,对着一张灰卡或者叶片区域做一次基准校正。镜头前加圆偏振片(CPL)可以减少叶片表面的高光反射,让果实颜色更饱和。注意偏振片会吃掉 1~2 挡进光量,阴天拍摄时要么拆掉,要么配合补光灯。这个坑在实验室里永远遇不到,只有在太阳底下跑系统才会暴露。
5.3 叶片遮挡让同一颗果子一会有一会无:多帧记忆与多视角
现象:果实被叶子遮住时检测框消失,风把叶子吹开后又出现,机械臂执行到一半失去目标,干脆停下报警。
原因:单帧检测模型在严重遮挡时的召回率天然偏低,模型没有“这地方刚才有颗果子”的状态记忆。
解决:接追踪器并给目标设置 2~3 秒的生命周期。当前帧检测不到时,沿用上一帧坐标并标记为“推测状态”,推测状态持续超过生命周期再删除。同时用深度图判断果实和遮挡叶子的前后关系——如果深度图上目标区域被一片更近的叶子覆盖,则表明果实被遮挡,不急着更新位置。条件允许的话在平台低位再加一个侧向相机补盲区,效果比任何算法都直接。
5.4 果园里标定板没法用:ArUco 标记与场景参照物
现象:棋盘格标定板在果园里被风吹倒、沾上泥,打印的角点反光识别失败,采集中途标定失效。
原因:标准棋盘格要求平面平整、对比度高、画面完整。果园地面不平,光线直射,叶片还时不时挡住半块板子,现场条件满足不了。
解决:改用 ArUco 码。ArUco 对部分遮挡鲁棒,即使叶子挡住一半也能识别出来,而且单个标记就能提供位姿,不用像棋盘格那样必须看到完整角点阵。做法是打印几张不同尺寸的 ArUco 码,贴在硬质板上,插入到工作区域显眼的位置,用cv2.aruco.detectMarkers实时检测并求位姿。田间快速恢复外参时,还可以找两个已知距离的固定参照物(果箱、支架立柱)做尺度估计,先恢复姿态再现场微调。
5.5 实验室精度高、下地就不行:品种差异与光照域迁移
现象:验证集 mAP 0.92,拿到目标果园同一天晴天测试,检出率掉到 0.6 以下;换个品种的果园更是惨不忍睹。
原因:深度学习模型对训练集的成像条件很敏感。实验室样本的相机型号、光源色温、背景纹理和果园现场差得远,模型记住的是“实验室内的一套外观”,而不是果实本身的普遍特征。这就是典型的域迁移问题。
解决:把测试结果按“同园同品种、同园异品种、异园同品种”三组分别统计。如果同园异品种掉得厉害,说明模型只记住了表面颜色纹理,需要补该品种的样本微调;如果异园同品种掉得厉害,说明光照和背景变了,要去目标果园先拍 500 张左右图,做一轮快速标注再微调。下地之前,尽量用目标果园的现场图做最后验证,不要拿实验室照片做结果汇报。
6. 从试验田到连续作业:模型轻量化、验证路径与数据回灌
6.1 用剪枝、量化和 TensorRT 把模型压到能上边缘设备
采摘机器人上常见的边缘设备是 Jetson 系列或工控机加显卡,算力比实验室的 GPU 弱很多。YOLOv8n 导出 ONNX 后,在 Jetson 上用 TensorRT 转成 FP16 引擎,通常能把推理时间压到十几毫秒级别。命令很简单:
trtexec --onnx=best.onnx --fp16 --saveEngine=best_fp16.engine不建议一上来就做 INT8 量化,果园场景光照变化大,INT8 需要带标定的校准集,做不好会让召回率掉几个点。先上 FP16,实测召回率和 FP32 基本一致。如果算力仍然紧张,再考虑对不重要的卷积层做剪枝,但剪枝后的模型要重新微调,时间成本不低。我的原则是:能通过换小模型解决的问题,不优先用剪枝解决。
6.2 下地前先做视觉分离验证:不看机械臂,只看“判得准不准”
视觉系统最忌和机械臂一起联调,因为问题会被互相掩盖。下地之前,先单独把视觉系统跑在目标果园的实拍视频上,连续回放一整天的数据,人工核对每一帧的检测、成熟度和坐标输出。推荐的验收指标如下:
| 指标 | 推荐目标 | 说明 |
|---|---|---|
| 果实检出召回率 | ≥ 0.95 | 每棵树上的果实有没有查全 |
| 误检次数 | 每天 ≤ 5 次 | 叶片被当成果实算误检 |
| 成熟度一致率 | ≥ 0.90 | 和人工判断结果比对 |
| 定位误差均值 | ≤ 2 cm | 与实测坐标比对,可接受范围按果实大小调整 |
这个阶段不花机械臂一分钱,但能暴露检测、标定、深度映射里的大部分问题。等离线视频验证通过,再做在线空跑和实际采摘。很多人把顺序搞反,一上来就全系统联调,出了问题根本分不清是视觉错还是机械臂错。
6.3 错例集回灌:让模型在采摘季里越用越准
系统上线后,模型还会遇到训练时没见过的场景,比如新品种、新光照条件。所以每天下地回来,把当天被判错的图像导出,人工修正标注,积累成一个“错例集”。错例集积累到 200 张左右,就可以触发一次增量微调。训练脚本不变,只是在原权重基础上继续训几十个 epoch。
我习惯把训练分成采摘季前、季中、季后三个版本:第一版用于测试,第二版根据错例集修正,第三版做全年数据全量重训。真正让系统稳定下来的往往不是某个模型结构,而是这套“采集-错例-重训”的循环。错例集比公开数据集值钱,它是现场真实分布的浓缩。希望你从这篇笔记开始,把视觉部分先独立跑通,再让机械臂慢慢跟上,能少走不少弯路。希望帮到你。
本文还有配套的精品资源,点击获取