ARTICLE DETAIL

资讯详情

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

双目相机SLAM实战:尺度恢复、标定与多传感器融合

双目相机SLAM实战:尺度恢复、标定与多传感器融合 双目相机在SLAM里到底解决了什么问题一句话它把单目SLAM最要命的“尺度漂移”和“初始化靠运气”这两个坑给填上了。但代价也很直接——标定麻烦、算力翻倍、深度图在弱纹理区域基本不可用。我前后用双目跑过室内建图、AGV导航和机械臂抓取几个场景踩过的坑从标定板反光到视差图整片空洞都有。这篇就把双目在SLAM与三维建图里的尺度恢复、精度边界和融合方法拆开讲清楚包括标定实操、视差计算、和IMU/激光的融合思路以及双目与3DGS结合这类新玩法。不管你是刚看完《视觉SLAM十四讲》想上手实机还是已经在调ROS建图包但被尺度问题卡住下面这些内容都能直接拿去用。1. 双目为什么能定尺度从视差到深度的完整推导1.1 单目的尺度困境与双目的破局点单目SLAM的根本问题在于从一张图像里你无法区分“一个真实的大物体在远处”和“一个小物体在近处”因为投影过程把尺度信息丢掉了。这就是所谓的尺度不确定性。单目跑出来的轨迹和地图整体可以任意缩放你没法知道机器人到底走了1米还是10米。常见的补救办法是初始化时假设一个已知位移或者靠IMU提供加速度积分来定尺度但前者脆弱、后者漂移快。双目从硬件层面直接解决了这个问题。两个相机之间有一个固定的物理距离叫基线baseline通常用b表示。这个基线就是一个已知的、物理意义上的长度参照。只要你能在左右图中找到同一个空间点在两幅图上的像素位置差视差就能通过三角测量算出这个点到相机的真实距离。尺度不再是猜的而是算出来的。1.2 三角测量的数学过程设左相机光心为原点右相机光心在x轴正方向偏移b。一个空间点P在左图成像坐标为(u_L, v_L)在右图为(u_R, v_R)。理想情况下两相机已校正、光轴平行、极线水平同一个点的v坐标相同只有u方向有差异视差d u_L - u_R。深度Z的公式非常简洁Z (f * b) / d其中f是焦距像素单位b是基线米d是视差像素。这个公式说明几件事深度和视差成反比视差越大物体越近深度越小视差趋近于0时深度趋于无穷也就是远处物体几乎测不准。这就是为什么双目在远距离精度急剧下降——视差只有一两个像素时一个像素的误差就能让深度翻倍。举个具体数字。假设f 700像素b 0.12米。一个点在视差d 60像素处Z 700×0.12/60 1.4米。如果视差测量误差是0.5像素那么d变成59.5或60.5Z在1.388到1.412米之间波动误差约±1.2厘米。但如果这个点在d 3像素处Z 28米0.5像素误差会让Z在24到33.6米之间跳误差好几米。所以双目的有效测距范围是有限的工程上一般把视差小于1像素的点直接丢弃。1.3 基线怎么选一个被低估的设计决策很多人拿到双目模组就直接用没想过基线是可以选的。基线大小直接决定了测距范围和精度分布。基线越大同样距离下的视差越大远距离精度越好但近处盲区也越大太近的物体在左右图中视差超过图像宽度匹配不上。基线越小近处表现好但远处基本没用。我一般这样估算如果应用最远要测Z_max允许的最小可靠视差是d_min通常取2像素那么需要的基线是 b Z_max × d_min / f。反过来最近距离Z_min对应的最大视差不能超过图像宽度W即 b Z_min × W / f。这两个约束一夹基线范围就出来了。实际产品里手机上的双目基线可能只有几毫米到十几毫米扫地机上的可能5到10厘米车载的能到几十厘米甚至更大。选基线本质上是在“看得远”和“看得近”之间做权衡没有万能值。2. 标定这件事双目精度的地基也是最容易翻车的地方2.1 双目标定到底在标什么双目标定要拿到两类参数。第一类是每个相机自己的内参焦距f_x、f_y主点c_x、c_y以及畸变系数径向k1、k2、k3切向p1、p2。第二类是两个相机之间的外参旋转矩阵R和平移向量t其中t的模长就是基线。标定的目标是让左右图像经过校正后同一个空间点的对应像素落在同一水平线上极线校正这样视差搜索就从二维降到一维效率和准确率都大幅提升。标定质量直接决定后面所有环节的上限。标定不准视差图就是错的深度就是错的SLAM的尺度就是错的而且这种错误是系统性的后面怎么调算法都补不回来。2.2 标定实操从采集到验证的完整链路我用得最多的是张正友标定法的实现OpenCV的stereoCalibrate配合calibrateCamera或者ROS里的camera_calibration包。流程大致如下。准备一块标定板棋盘格或圆点阵都行棋盘格更常见。关键是板的平整度打印后必须贴在硬质平板上我用的是铝板加背胶纸板受潮会翘翘了标定就废。格子尺寸要实测别信打印标称值用卡尺量几个格子的实际边长取平均。采集图像时左右相机要同步拍同一块板。板要在画面里覆盖不同位置、不同角度、不同距离一般每个相机采15到30对有效图像。覆盖要均匀四个角、中心、边缘都要有倾斜角度从正对到45度左右都要有。我见过有人只在画面中间正对着拍十几张标定出来的畸变系数完全是错的边缘畸变根本没被约束到。采集时有个大坑标定板反光。如果板面是光面纸灯光一打就有高光角点检测直接失败或者偏移。解决办法是用哑光纸打印或者调整光源角度避开镜面反射。另一个坑是运动模糊手持拍摄时快门太慢角点糊成一团。要么用同步触发要么保证曝光时间足够短。采集完跑标定OpenCV的核心调用大概是这样# 单目标定分别得到左右相机内参 retL, mtxL, distL, _, _ cv2.calibrateCamera(objpoints, imgpointsL, imgSize, None, None) retR, mtxR, distR, _, _ cv2.calibrateCamera(objpoints, imgpointsR, imgSize, None, None) # 双目标定固定内参求外参 ret, mtxL, distL, mtxR, distR, R, T, E, F cv2.stereoCalibrate( objpoints, imgpointsL, imgpointsR, mtxL, distL, mtxR, distR, imgSize, flagscv2.CALIB_FIX_INTRINSIC)CALIB_FIX_INTRINSIC这个flag很关键。先用单目标定把内参固定住再只优化外参比一次性全优化更稳定不容易过拟合。如果内参本身标得不好也可以放开一起优化但要有足够多的图像约束。2.3 标定结果怎么判断好坏标定完不能直接信必须验证。几个关键指标重投影误差RMS reprojection error是最直接的。OpenCV会返回这个值单位是像素。一般来说小于0.5像素算不错小于0.3像素算很好。但要注意这个误差是在标定集上的如果采集图像太少或分布不均误差小也可能是过拟合。基线长度要和实测对比。标定出来的T向量的模长就是基线拿卡尺量一下两个镜头光心的实际距离差太多说明标定有问题。不过镜头光心位置不好直接量可以量外壳上标记点再估算误差在几毫米内可接受。极线校正效果要肉眼验证。用stereoRectify算出校正映射把左右图校正后叠加看同一个物体是不是在同一水平线上。我通常会把校正后的左图取红色通道、右图取绿色通道合成一张图如果边缘处红绿分离明显说明校正不准。提示标定不是一劳永逸的。相机摔过、温度变化大、镜头松动都会让外参漂移。工业场景里我一般每隔几个月复标一次或者用在线自标定做补偿。3. 视差计算与深度图精度到底卡在哪里3.1 立体匹配的基本流程有了校正后的图像下一步是逐像素找左右对应点算视差。经典流程是计算匹配代价比如Census变换、SAD、AD代价聚合在支持窗口内平滑视差计算赢家通吃或亚像素插值视差优化左右一致性检查、空洞填充、中值滤波。OpenCV里StereoBM和StereoSGBM是两个常用实现。BM快但质量一般SGBM慢但半全局优化后效果好很多。参数里numDisparities视差搜索范围必须是16的倍数blockSize是匹配窗口大小这两个对结果影响最大。stereo cv2.StereoSGBM_create( minDisparity0, numDisparities128, # 视差搜索范围决定最近可测距离 blockSize5, # 匹配窗口越大越平滑但边缘越糊 P18*3*5**2, P232*3*5**2, uniquenessRatio10, speckleWindowSize100, speckleRange2, disp12MaxDiff1) disparity stereo.compute(imgL, imgR).astype(np.float32) / 16.0numDisparities决定了最近能测多近。视差搜索范围是0到numDisparities如果真实视差超过这个范围近处物体就匹配不上。所以要根据基线和工作距离反推最近距离Z_min对应的视差d_max f×b/Z_minnumDisparities要大于d_max。3.2 弱纹理、重复纹理和遮挡双目深度的三大天敌双目深度图在实验室里看着漂亮一到真实场景就千疮百孔。主要三个原因。弱纹理区域比如白墙、纯色桌面、玻璃左右图里这块区域长得一模一样匹配算法找不到唯一对应点视差图就是一片空洞。这是双目最本质的缺陷靠算法很难根治只能靠增加纹理投影散斑或者融合其他传感器。重复纹理比如栅栏、瓷砖、键盘匹配算法容易把左边第3根栅栏匹配到右边第4根视差算错深度直接跳变。这种错误往往还通不过左右一致性检查会被标记为无效但偶尔也会漏网。遮挡区域左相机能看到但右相机看不到的地方因为基线存在视差这些点在右图里根本不存在自然算不出视差。遮挡区通常在物体边缘宽度和基线、深度有关。3.3 从视差图到点云精度评估的实操方法拿到视差图后用reprojectImageTo3D配合Q矩阵由stereoRectify得到就能生成三维点云。但点云质量参差不齐得会评估。我的做法是放几个已知尺寸的标定物在场景里比如一个边长10厘米的立方体测出来的点云里量它的边长看误差多少。再放一个已知距离的平面看点云的平面度。这样能快速判断当前参数下的实际精度比看论文里的指标实在。深度精度和距离的平方成反比这是三角测量的固有特性。距离翻倍深度误差大约变成4倍。所以别指望双目在5米外还有厘米级精度除非基线很大。工程上我会给深度图加一个置信度视差大、匹配代价低的点置信度高反之丢弃。4. 双目与SLAM的结合尺度恢复与位姿估计4.1 双目SLAM相比单目多了什么单目SLAM的框架特征提取、匹配、运动估计、局部优化、回环双目都能用但多了几样东西。第一初始化不再需要专门的运动来三角化第一帧就能直接算出深度系统启动即稳定。第二尺度可观地图和轨迹都是真实尺度直接能用于导航和控制。第三深度信息让特征匹配和位姿估计更鲁棒尤其是纯旋转运动时单目会退化双目不会。代价是计算量。双目要处理两倍图像还要算视差前端开销大概翻倍。所以双目SLAM对算力要求更高嵌入式平台上要仔细优化。4.2 ORB-SLAM系列里的双目模式ORB-SLAM2和ORB-SLAM3都支持双目。它的做法是在左右图上分别提取ORB特征然后通过极线约束在右图对应极线上找匹配得到带深度的特征点。这些三维点直接进入地图用于后续的PnP位姿估计和局部BA。实际跑的时候双目模式比单目稳很多尤其是快速运动和纹理一般的场景。但ORB特征本身在弱纹理下也少所以白墙场景还是难。另外ORB-SLAM的双目对同步要求高左右图时间戳差太多匹配就错。4.3 尺度漂移双目也不是完全免疫很多人以为双目定了尺度就一劳永逸其实不然。双目的尺度是标定给的如果标定不准或者外参漂移尺度就是错的。而且长时间运行后累积误差会让轨迹整体偏移虽然尺度比例大致对但绝对位置会漂。回环检测和全局BA能修正一部分但前提是能检测到回环。我遇到过一次典型问题机器人跑了一个大圈回到起点轨迹在z轴高度上漂了将近20厘米。排查下来是标定时基线估计偏小导致所有深度系统性偏近累积后高度就漂了。重新标定后问题消失。所以双目的尺度精度本质上还是标定精度。5. 多传感器融合双目IMU激光的实战组合5.1 为什么单靠双目不够双目在纹理丰富、光照稳定的场景表现很好但遇到弱纹理、强光、快速运动就掉链子。IMU提供高频的角速度和加速度能在图像帧之间做积分补上运动估计的空档还能在视觉失效时短时维持。激光雷达提供直接的距离测量不受纹理和光照影响但点云稀疏、频率低。三者互补融合后鲁棒性大幅提升。5.2 视觉惯性融合的两种耦合方式松耦合是把视觉位姿和IMU积分分别算出来再用滤波如EKF融合。实现简单但视觉失效时IMU单独积分漂移快。紧耦合是把视觉重投影误差和IMU预积分误差放在同一个优化问题里联合优化精度和鲁棒性都更好但实现复杂。VINS-Mono、ORB-SLAM3的IMU模式都是紧耦合。双目IMU的紧耦合相比单目IMU优势在于尺度直接可观不需要靠IMU激励来初始化尺度启动更快更稳。而且双目提供的深度约束让IMU的零偏估计更准。5.3 双目与激光的融合各取所长激光雷达在结构化的室内环境里建图精度很高但点云稀疏远距离和玻璃、镜面会失效。双目提供稠密深度但精度和范围有限。融合的思路通常是用激光提供精确的几何骨架用双目补充稠密的纹理和近处细节。一种实用做法是把双目生成的点云和激光点云做配准ICP或其变种用激光修正双目的尺度漂移用双目填补激光的稀疏区。另一种是在因子图里激光里程计和双目视觉里程计各作为一个因子联合优化。ROS里可以用robot_localization做松耦合或者用LIO-SAM这类框架的思路扩展到视觉。5.4 融合时的坐标系与时间同步融合最容易翻车的地方不是算法是标定和时间同步。双目和IMU之间的外参相机到IMU的旋转和平移必须标定而且要在时间上对齐。IMU频率通常100到1000Hz图像10到30Hz时间戳差几毫秒在快速运动时就会引入明显误差。我的经验是硬件触发同步最可靠软件时间戳对齐只能凑合。外参标定可以用Kalibr这类工具但标定质量依赖激励的充分性要各个轴都转动到。标定完同样要验证把融合轨迹和纯视觉轨迹对比看是否更平滑、回环误差是否更小。6. 双目与3DGS、机器人导航的落地场景6.1 双目3DGS用深度先验加速重建3D高斯泼溅3DGS这两年在三维重建里很火但它原本依赖SfM给的稀疏点云做初始化重建质量和速度受SfM影响大。双目能直接提供带尺度的稠密深度用来初始化高斯点收敛更快尺度也天然正确。实际做法是把双目深度图反投影成点云作为3DGS的初始点集再配合多视角优化。这样省掉了SfM那一步对弱纹理场景也友好一些因为深度先验补上了SfM失败的区域。6.2 ROS里的双目建图与自主导航ROS生态里双目建图常用RTAB-Map或ORB-SLAM的ROS封装。RTAB-Map支持双目输入能建稠密点云和栅格地图配合move_base或nav2做导航。流程是双目驱动发布左右图像和相机信息RTAB-Map订阅后做视觉里程计和回环输出地图和TF导航栈用地图做路径规划。实际部署时几个注意点双目驱动要保证左右图时间戳一致TF树要正确相机到base_link的外参要标定地图分辨率别设太细否则内存爆炸。我一般用5厘米分辨率的栅格地图够导航用点云另存。6.3 精度与算力的平衡取舍双目SLAM建图在嵌入式平台上跑算力永远是瓶颈。我的取舍原则是前端特征点数量控制在合理范围比如每帧500到1000个视差图分辨率可以降采样回环检测频率降低但别关。如果平台实在太弱可以只在关键帧算稠密深度普通帧只用稀疏特征。注意双目系统的性能上限由标定决定下限由融合策略决定。标定做扎实融合做合理比堆算法参数有用得多。7. 几个我踩过的坑和对应的排查思路7.1 视差图整片空洞先查标定再查参数有次新装的双目模组视差图几乎全黑只有零星几个点。第一反应是算法参数不对调了半天没用。后来用校正后的图像做红绿叠加发现左右图根本没对齐极线校正就是错的。根因是标定图像采集时标定板有反光角点检测偏移外参算错了。重新用哑光板标定后视差图立刻正常。所以遇到视差图异常第一步永远是验证极线校正别急着调SGBM参数。7.2 深度系统性偏近或偏远基线或焦距错了如果所有深度都偏一个固定比例多半是基线或焦距标定有误。深度和f×b成正比f或b偏小深度就偏小。排查方法是放一个已知距离的物体测出来的深度和真实值比算出比例因子再反推是f还是b的问题。如果是b错了重新标定外参如果是f错了检查内参标定。7.3 运动时深度跳变同步或曝光问题机器人一动深度图就乱跳静止时正常。这通常是左右相机不同步或者曝光时间不一致。运动时左右图拍的不是同一时刻的场景匹配自然错。解决办法是硬件同步触发或者至少保证曝光参数一致。如果相机支持用全局快门而不是卷帘快门卷帘快门在运动时会有果冻效应同样影响匹配。7.4 融合后轨迹反而变差外参或时间戳的锅双目IMU融合后轨迹精度反而不如纯双目这种情况我遇到过两次。一次是相机到IMU的外参标定错了旋转矩阵差了几度融合时两个传感器互相打架。另一次是时间戳没对齐IMU数据比图像早了十几毫秒快速旋转时误差被放大。排查方法是单独跑纯视觉和纯IMU看各自表现再检查外参和时间戳。融合系统的调试永远先把单传感器调好再调融合。双目相机在SLAM和三维建图里的价值说到底就是“用硬件换尺度用标定换精度用融合换鲁棒”。它不是什么场景都最优弱纹理和远距离是它的硬伤但在中近距离、纹理尚可的场景里它是性价比很高的稠密深度来源。我个人在实际项目里的体会是把标定做扎实把同步做严格把融合策略做合理双目的表现会比大多数人的预期好很多反过来标定糊弄、同步凑合再好的算法也救不回来。后续如果要在双目基础上做扩展我建议优先考虑和IMU的紧耦合以及用双目深度去初始化3DGS这类重建管线这两条路目前看落地价值最高。
返回列表