ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

双目立体视觉在果蔬采摘中的三维定位与工程实现

双目立体视觉在果蔬采摘中的三维定位与工程实现 简介这是一份关于计算机视觉在果蔬机械采摘中应用研究的中文期刊论文PDF面向现代农业工程、计算机视觉及自动化采摘方向的研究者、工程师和毕业设计学生。文章针对人工采摘效率低、目标识别困难等痛点给出了基于双目立体视觉的完整解决方案先介绍由成像装置和计算机构成的视觉系统工作原理再推导双目摄像机参数与目标点三维坐标的数学模型含焦距、中心距、视差公式随后给出机械采摘系统的硬件组成与软件流程设计并通过仿真验证了目标识别与定位精度。该PDF为参考文献类资源共1个文件大小1.35MB包含完整的摘要、引言、原理推导、图表及结论可直接用于课题调研、论文引用或系统开发参考。目前已有91人学习浏览适合需要快速理解计算机视觉采摘原理并落地应用的读者。1. 计算机视觉在果蔬机械采摘中的应用研究不止是识别更是三维定位这篇论文的题目看起来像是一篇常规的综述但实际拆解下来它是一个完整的双目立体视觉采摘系统设计核心落在「如何把图像上的果实像素变成机械臂能用的三维坐标」这一件事上。论文里给出了完整的数学模型、硬件组成、软件流程和仿真实验数据尤其是对橙子目标的识别实验正常识别率做到了 98.6%单果采摘速度 25 秒。这几个数字意味着什么意味着这套方案不仅有理论价值而且已经具备工程复现的基础。适合正在做农业机器人、采摘机械臂或者双目视觉定位的从业者作为系统设计参考也适合刚入门计算机视觉的人去理解从图像到三维坐标的完整链路。2. 双目立体视觉的数学模型先看懂 Z bf/(x1-x2) 再说选型2.1 为什么采摘场景必须用双目而不是单目很多初学者会问单目相机加深度学习能不能做目标定位能测距离但精度和稳定性在农业采摘场景里远远不够。原因是单目测距依赖先验尺寸或者地面平面假设而果蔬的形状本身不规则尺寸差异大果实又会被枝叶遮挡单目的深度估计在遮挡和形变面前非常容易飘。论文里选的是双目立体视觉方案本质上是模拟人的双眼通过两个位置固定的相机同时拍摄利用视差来恢复深度信息。这套方案结构简单对环境光照有一定容忍度而且不需要额外主动光源适合户外果园这类非受控环境。双目方案的核心在于视差计算。所谓视差就是同一个目标点在左右两张图像上横坐标的差值。目标距离越近视差越大距离越远视差越小。论文里的模型假设两个摄像机焦距相同、内参数一致、光轴平行这就是标准的理想双目模型。虽然实际装配不可能做到绝对平行但这个假设的价值在于先把核心关系理清剩下的误差交给标定去修正。2.2 从成像平面到世界坐标公式推导与物理意义论文里的模型图是一个典型的双目汇聚模型。两个焦距为 f 的摄像机中心相距 b目标点 P 在左右成像平面上的投影点分别是 P1(x1, y1) 和 P2(x2, y2)。利用三角相似原理可以推出目标点到两个摄像机中心连线的距离 dd bf / (x1 - x2)分母 x1 - x2 就是视差。从这个公式能直观地感受到当视差接近零时深度趋向无穷大这意味着远处的物体深度估计极不稳定当视差很小时深度对像素误差极度敏感哪怕一个像素的误匹配可能造成几厘米甚至十几厘米的定位误差。这也是为什么论文里强调目标识别和定位是采摘系统的核心——识别不准视差就算错了视差错了机械臂抓取位置就偏了。进一步推导可以得到目标点在世界坐标系下的完整坐标X b(x1 x2) / [2(x1 - x2)] Y b(y1 y2) / [2(y1 - y2)] Z bf / (x1 - x2)这三个式子是整个采摘系统定位模块的计算核心。在实际代码实现中只要标定得到 f 和 b再通过匹配得到 (x1, y1) 和 (x2, y2)就能算出目标的三维坐标。这里有一个工程上必须注意的细节论文里的公式是一个理想模型实际摄像机存在畸变、光轴不完全平行、左右视角不一致等问题。如果直接套公式误差会非常大。我的实际操作流程是先用相机标定得到内参和畸变系数再做立体校正把左右图像校正成理想双目模型的状态然后再用这套公式。不校正直接算就是纸上谈兵出来的坐标机械臂根本不敢用。2.3 基线距离 b 和焦距 f 怎么选不要拍脑袋定参数基线距离 b 是双目系统里最关键的硬件参数。基线太长近距离目标的视差过大可能会超出搜索范围而且左右视角差异太大遮挡区域不一致匹配困难基线太短视差太小深度分辨率不够。从公式 d bf/(x1-x2) 来看b 和 f 对深度的贡献是乘在一起的。实际项目里我会根据工作距离来定如果采摘机器人的作业距离在 0.5 到 2 米之间基线 b 选 10 到 30 厘米比较合适。焦距 f 由相机镜头决定像素分辨率越高、镜头焦距越长深度精度越好但视场角变小寻找目标的难度变大。这是一个权衡没有绝对最优解。选型时还有一个容易忽略的点两个相机的型号必须一致包括感光芯片、镜头焦距、分辨率。如果左右相机型号不同即使标定也很难把两者拉到同一个成像模型下。论文里明确写了「两个摄像机的焦距和内参数完全相同」这在硬件选型时就要保证而不是靠后期软件去补偿。3. 系统硬件与软件设计从标定到识别的完整链路3.1 硬件架构与相机标定实操论文里把机械采摘系统分成了三块计算机视觉系统、控制系统和机械臂系统。这个划分很清晰各司其职。计算机视觉系统做图像采集和目标定位控制系统做运动控制和决策机械臂系统负责执行。在实际搭建中我建议把视觉系统和控制系统分两台机器跑因为视觉的算法计算量较大PLC 处理不了图像数据。论文里用的方案是工控机接收图像数据处理后通过数据转换模块传给 PLC 控制器这个分工合理能避免实时性冲突。相机标定是整个视觉系统里第一个绕不过去的事。前面说了直接套理想模型公式会偏而标定的目标就是拿到两个相机各自的内参、畸变系数以及两相机之间的相对位姿关系 R 和 T。标定完之后还要做立体校正这一步很多人会漏掉。不校正的话左右图像的行不对齐匹配搜索就得在二维范围里做计算量和误匹配率都会上升。以下是我常用的标定流程用 OpenCV 实现采集约 20 对棋盘格图像检测角点后做立体标定import cv2 import numpy as np import glob # 棋盘格内角点数这里假设 9x6 pattern_size (9, 6) # 准备世界坐标系中的棋盘点 objp np.zeros((pattern_size[0] * pattern_size[1], 3), np.float32) objp[:, :2] np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2) obj_points [] left_points [] right_points [] left_images sorted(glob.glob(left/*.jpg)) right_images sorted(glob.glob(right/*.jpg)) for lf, rf in zip(left_images, right_images): img_l cv2.imread(lf) img_r cv2.imread(rf) gray_l cv2.cvtColor(img_l, cv2.COLOR_BGR2GRAY) gray_r cv2.cvtColor(img_r, cv2.COLOR_BGR2GRAY) ret_l, corners_l cv2.findChessboardCorners(gray_l, pattern_size) ret_r, corners_r cv2.findChessboardCorners(gray_r, pattern_size) if ret_l and ret_r: obj_points.append(objp) # 亚像素角点检测提高标定精度 criteria (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) corners_l cv2.cornerSubPix(gray_l, corners_l, (11, 11), (-1, -1), criteria) corners_r cv2.cornerSubPix(gray_r, corners_r, (11, 11), (-1, -1), criteria) left_points.append(corners_l) right_points.append(corners_r) # 单目标定 ret_l, mtx_l, dist_l, _, _ cv2.calibrateCamera(obj_points, left_points, gray_l.shape[::-1], None, None) ret_r, mtx_r, dist_r, _, _ cv2.calibrateCamera(obj_points, right_points, gray_r.shape[::-1], None, None) # 立体标定 criteria (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) ret_s, mtx_l, dist_l, mtx_r, dist_r, R, T, E, F cv2.stereoCalibrate( obj_points, left_points, right_points, mtx_l, dist_l, mtx_r, dist_r, gray_l.shape[::-1], criteriacriteria ) # 极线校正 R1, R2, P1, P2, Q, _, _ cv2.stereoRectify( mtx_l, dist_l, mtx_r, dist_r, gray_l.shape[::-1], R, T, alpha0 ) # 计算校正映射表 map1_l, map2_l cv2.initUndistortRectifyMap(mtx_l, dist_l, R1, P1, gray_l.shape[::-1], cv2.CV_32FC1) map1_r, map2_r cv2.initUndistortRectifyMap(mtx_r, dist_r, R2, P2, gray_r.shape[::-1], cv2.CV_32FC1) # 保存参数备用 np.savez(stereo_params.npz, mtx_lmtx_l, dist_ldist_l, mtx_rmtx_r, dist_rdist_r, RR, TT, R1R1, R2R2, P1P1, P2P2, QQ)标定结果里最需要关注的指标是重投影误差一般要求小于 0.5 像素。如果误差偏大先检查棋盘格图像的数量和姿态覆盖范围。20 对图像已经算少的最好有 25 到 30 对而且棋盘格姿态要包含左倾、右倾、前倾、后倾不能只放在一个角度上。另一个检查项是极线校正结果把左右图像用 remap 校正后叠加在同一个画布里用鼠标取一个目标点看它在右图同一行上是否出现在对应位置。如果行对齐有偏差机械臂的抓取位置就会出现系统性偏移。标定的环境也要稳定。我遇到过在室内标定好好的参数带到室外果园就漂移的情况原因是温度变化引起镜头轻微变形虽然在可见光波段不至于特别严重但高精度定位下问题会被放大。有条件的话在果园现场或者至少同一温度环境下标定一次。3.2 图像预处理与目标分割HSV 空间里做阈值最稳论文里说计算机视觉系统要进行图像的低层处理、特征提取和模式识别放在实际代码里就是图线预处理、分割和轮廓分析。这篇论文的实验对象是橙子颜色特征非常明显所以分割环节的核心策略是颜色空间选择。RGB 空间直接做阈值分割在果园这种自然光环境下非常脆弱光照稍微变化三个通道一起漂阈值根本稳不住。我一般会转到 HSV 空间用 H色调通道做主分割依据S饱和度通道做辅助过滤。橙子的 H 值大致在 10 到 25 之间OpenCV 中 H 范围是 0 到 180成熟度和光照不同会有偏移。分割前先做一次双边滤波既能去噪又能保住边缘细节。太大尺寸的中值滤波会把轮廓磨圆边缘糊掉几个像素虽然视觉上看着干净但后续的视差计算和定位精度要打折扣。以下是我常用的预处理和分割代码import cv2 import numpy as np def segment_orange(image_bgr): # 转 HSV 空间 hsv cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV) # 双边滤波d 是邻域直径sigmaColor 和 sigmaSpace 控制平滑程度 hsv cv2.bilateralFilter(hsv, 9, 50, 50) # 橙子色范围实际使用时需要根据光照环境微调 lower np.array([8, 80, 120]) upper np.array([30, 255, 255]) mask cv2.inRange(hsv, lower, upper) # 先开运算去掉小噪点再闭运算填充果实内部的空洞 kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 用连通域面积过滤去掉叶片反光等小干扰区域 contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) clean_mask np.zeros_like(mask) for c in contours: area cv2.contourArea(c) if area 500: # 阈值按图像分辨率调整 cv2.drawContours(clean_mask, [c], -1, 255, -1) return clean_mask这段代码里最需要现场调的就是 HSV 阈值范围。我自己的习惯是先用一个带滑动条的小工具把上下限调到当前环境的最优值再固化到配置文件里。如果分割出来果实区域有大量空洞说明闭运算的核太小如果粘连严重说明阈值范围太宽把叶片反光也收进来了。面积阈值 500 是按一张 1920x1080 的图像设置的分辨率变了要按比例调。分割完之后目标区域就已经拉出来了。这个时候可以做轮廓分析用面积、圆度、凸包等特征进一步过滤。橙子的轮廓圆度特征非常明显细长的枝叶轮廓圆度低容易被滤掉。这一步虽然简单但在复杂背景下能有效减少确认目标的数量给后面的立体匹配降低压力。3.3 目标识别与立体匹配先分割再匹配避免稠密视差的坑论文里的识别流程是先识别目标再做立体匹配。这一步的顺序问题很多人容易搞反。如果直接用稠密立体匹配算法比如 SGBM对整张图像算视差图果园这种纹理复杂、遮挡严重的场景会出现大量错误视差果实边缘的视差尤其不稳定。正确做法是先做目标分割把每个果实作为独立区域提取出来然后再对区域做匹配。我的做法是左右图像各自做分割拿到果实区域的轮廓和质心坐标然后以左图的质心为中心在右图的同一行附近搜索最相似的区域。由于立体校正后左右图像的行已经对齐匹配搜索只需要在一维方向上进行视差的计算就变成了左右质心横坐标的差值。import numpy as np def match_fruit_centroids(left_mask, right_mask, max_disp150): # 提取左右图像中的目标质心 def get_centroids(mask): contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) centroids [] for c in contours: M cv2.moments(c) if M[m00] 0: continue cx int(M[m10] / M[m00]) cy int(M[m01] / M[m00]) area cv2.contourArea(c) centroids.append((cx, cy, area)) return centroids left_centroids get_centroids(left_mask) right_centroids get_centroids(right_mask) matches [] for lc in left_centroids: best_match None best_score np.inf for rc in right_centroids: # 极线校正后同名点在同一行附近 if abs(lc[1] - rc[1]) 3: continue # 视差 x_left - x_right 必须是正值 d lc[0] - rc[0] if d 0 or d max_disp: continue # 用面积差异和距离做简单打分 score abs(lc[2] - rc[2]) abs(lc[1] - rc[1]) * 2 if score best_score: best_score score best_match (rc[0], rc[1], d, lc[2]) if best_match is not None: matches.append((lc, best_match)) return matches这段代码里我用了面积差异加纵向偏移做打分实际项目里可以换成局部灰度相关性。匹配完成之后视差 d 和标定得到的 f、b、Q 矩阵一起就能算出果实的三维坐标。如果匹配到的候选区域一左一右不只一个取打分最优的那一对然后检查一下左右图的面积差异是不是在一个合理范围两个摄像机看同一个果实面积不会差太多。如果面积差异超过 20%多半是误匹配。匹配的可靠性还有一个检查手段把左右图像和匹配结果可视化在左图中画出质心点在右图中画出对应的匹配点人眼扫一遍就能看出匹配是否正确。这一步看似笨但在真正去做机械臂抓取之前是必须做的因为一旦坐标错了机械臂会空抓或者撞到枝叶上。4. 仿真实验与识别率背后的细节从 317 个目标到 98.6% 识别率4.1 实验数据说明了什么论文的表 1 给出了一个很有意思的数据待识别采摘目标 317 个个体识别 317 个识别率 97.8%但正常识别个体只有 276 个识别率 98.6%被遮挡个体 41 个识别率 93.2%。这个数据的结构在真实果园里非常典型。正常识别的 276 个目标几乎全找到了说明颜色分割加轮廓识别在无遮挡条件下足够稳。被遮挡个体的识别率降到了 93.2%41 个里漏掉 3 个左右这个漏检基本都发生在果实大面积被叶片遮住、露出的面积太少的情况。这个数据给我们的启示是如果目标是提高整体识别率重点应该放在改善遮挡场景的处理上而不是去优化已经很稳的正常识别链路。一个常见的改进方向是增加遮挡判断逻辑——当某个候选区域的轮廓只有部分圆弧、边缘不完整时不要急着丢弃先做圆形拟合看残缺的部分能否补成一个合理果实。在机械采摘的实际设计中即使识别出来了还要输出形状描述给后续抓取做姿态参考所以这一步的止损策略很重要。4.2 从识别到定位面积过滤与边缘精度处理仿真实验里提到二值化图像后确定目标轮廓我实际做的时候会把处理流程进一步细化。轮廓确定之后要在左右图像中分别提取出一个可靠的参考点。这个参考点选择哪个位置直接影响最终的三维坐标精度。大多数论文里默认选质心也就是通过矩计算出来的区域中心。质心的优点是鲁棒性好受边缘噪声影响小但它的前提是目标区域是完整的。如果果实被遮挡质心会向未遮挡一侧偏移导致定位偏差。被遮挡的果实在抓取任务里难度本来就大机械臂很可能先处理那些完整暴露的果实。所以我在系统设计时会把目标分成普通目标和高遮挡目标两个状态队列。普通目标的质心直接作为抓取点高遮挡目标则触发拟合逻辑尝试用圆拟合恢复出完整轮廓再取圆心。如果拟合的结果连基本几何约束都过不了那就放弃这个目标进入下一轮扫描而不是让机械臂去抓一个不可靠的位置。4.3 采摘速度为 25 秒/个的瓶颈在哪里论文里提到单个采摘速度 25 秒这个数据是一整套流程的时间开销不只是视觉识别。从移动平台到目标附近、识别目标、定位、机械臂运动和夹取整个闭环 25 秒已经算不错了。但如果你要在实际果园里部署速度瓶颈往往不在视觉算法而在机械臂的运动轨迹规划。视觉处理整个链路如果优化得当单目标识别加定位可以做到 100 毫秒以内但机械臂从初始位置到目标点这一趟运动就得花十分之几秒到几秒加上夹持动作时间上去得很明显。从工程优化的角度减少采摘周期的重点在于让视觉系统提前工作。移动平台在朝一个方向行进时就开始预扫描下一批果实把识别和定位结果提前缓存机械臂一完成当前抓取动作立刻就能拿到下一个目标坐标不用等视觉现算。这种做法在论文里没有提但实际部署的时候几乎是必须的尤其是想提高整机效率。5. 避坑指南双目采摘系统最常见的五个翻车点5.1 标定板拍了几十张重投影误差还是很大现象标定出的重投影误差超过 1 个像素视差出来的深度值明显偏抖。 原因最典型的两个问题——棋盘格图像姿态覆盖不够角点集中在画面中央画面边缘区域的畸变参数拟合不出来另一个是棋盘格本身不平整打印在普通纸上贴在硬纸板上会有微小弯曲。 解决至少拍 25 到 30 对图像棋盘格要出现在画面的四个角和中心区域姿态要有前后倾斜和左右旋转。建议把棋盘格贴在亚克力板上避免纸张弯曲。标定完成后用 Remap 检查校正图像左右图的行对齐误差要小于一个像素。5.2 同一个果实左右图颜色差很多分割结果不一致现象左图能分割出果实右图分割不出来或者右图分割出的区域明显偏小。 原因两个相机的自动白平衡、自动曝光功能没有关闭。尤其在果园里左右相机的视角不同面对的光照方向和阴影分布不同自动曝光会让两边的亮度完全不一致同一个果实在左右图里的颜色值差别很大。 解决相机手动模式固定曝光时间和增益白平衡设置成固定色温值。采集前把两个相机对准同一片白墙或灰卡手动调一次白平衡参数之后锁定不变化。这一步做不好后续分割和匹配都是多米诺骨牌式翻车。5.3 视差计算正确但三维坐标在 Z 方向跳变明显现象目标不动输出的深度值在厘米级别来回跳。 原因基线短、分辨率低或者目标距离远视差只有几个像素像素级的量化误差直接放大到厘米级。从公式 Z bf/d 可以看出来视差 d 小的时候d 变化一个像素Z 的变化非常大。 解决一是增加基线距离二是提高相机分辨率或改用更长焦距的镜头三是在时间维度上加滤波对连续多帧的深度结果做滑动平均。我习惯对同一目标连续取 5 帧深度值去掉最大和最小之后取平均稳定性能提升很多。5.4 彩色摄像机在傍晚时光照严重不足分割率暴跌现象下午五六点之后果实和背景的对比度明显下降HSV 阈值还按白天的参数来分割结果一片糟。 原因自然光照的色温和强度在一天内是持续变化的没有加主动照明时HSV 区间固定不变早晚识别率下降是必然的。 解决一是在硬件上增加固定色温的 LED 补光灯让成像设备的照明相对稳定二是软件上做自适应阈值根据图像的平均亮度动态调整 HSV 下界的 V 值。这两种方案二选一或者一起用项目现场的稳定性才会好。5.5 机械臂抓取点偏差导致夹不到果实或者夹碎果子现象视觉输出的坐标在仿真里看着没问题机械臂实际抓过去偏了或者抓得太用力把果子夹坏。 原因视觉定位给出的是果实轮廓的质心这个点未必是机械臂最合理的抓取点。直径大的果实质心和果蒂方向的位置差别可能有好几厘米抓到果柄就很容易夹碎。 解决视觉系统除了输出质心坐标还要输出果实轮廓的最小外接圆半径和主轴方向给机械臂的运动规划一个参考姿态。抓取点的选择加入果蒂方向估计让夹持机构对着果实赤道方向接近而不是从顶部硬压下去。6. 进阶怎么把论文里的系统落成一套可验证的原型如果你想在实验室里复现这篇论文里的整套流程最简单的方式是先用仿真数据跑通算法链路。搭建一个两个虚拟相机对准橙子模型的场景采集左右视图跑通分割、匹配、深度计算验证三个坐标轴上的误差指标。这个过程用 OpenCV 加一个简单的 3D 渲染库就能完成不需要真实硬件。真正要做机械臂联动的时候再搭建真实双目平台替换掉仿真里的图像输入。论文中提到了摄像机标定是第一阶段的工作我在实际项目里会额外把标定结果存储成一份带时间戳的参数文件每次系统部署到新环境或者更换镜头之后强制重新标定一遍而不是沿用之前的参数。相机参数会随着运输颠簸、温度变化而漂移尤其螺丝固定的工业相机时间久了内参也会有微小的变化。从那以后我每次进入现场调试的第一步就是摆开棋盘格重新走一遍标定流程确认重投影误差在允许范围内才继续后面的工作这套习惯帮我少走了很多弯路希望也能帮到你。本文还有配套的精品资源点击获取
返回列表