双目ORB-SLAM2与EuRoC数据集实战:从环境配置到轨迹评估

📅 发布时间:2026/10/16 7:25:31
双目ORB-SLAM2与EuRoC数据集实战:从环境配置到轨迹评估
1. 为什么选择双目ORB-SLAM2与EuRoC数据集这个组合双目视觉SLAM一直是机器人、无人机、AR/VR领域里绕不开的一块硬骨头。单目SLAM存在尺度不确定和初始化漂移的问题RGB-D虽然能直接拿到深度但受限于红外结构光的测量距离和室外强光干扰真正在户外飞行的平台上双目方案才是更稳妥的选择。ORB-SLAM2作为视觉SLAM里被引用最多的开源框架之一它的双目模式在精度、鲁棒性和回环检测上都有比较成熟的表现而EuRoC MAV数据集则是苏黎世联邦理工发布的微型飞行器室内数据集自带双目灰度图、IMU数据以及运动捕捉系统提供的真值轨迹是验证双目SLAM算法最常用的基准之一。把这两者组合起来跑通意义在于你能在一个有真值参考的环境下完整地观察ORB-SLAM2的双目前端如何提取ORB特征、如何做双目立体匹配、如何通过特征点三角化恢复尺度以及后端如何做局部BA和回环优化。对于刚接触SLAM的开发者来说这是从理论走向工程实践的一条捷径对于已经做过单目SLAM的人来说切换到双目模式能帮你理解尺度恢复和立体匹配这两个关键环节的差异。这篇文章面向的是有一定C和Linux基础、想动手跑通双目SLAM的开发者。我会从环境准备、代码修改、参数配置、运行调试到结果评估把整个流程拆开讲清楚同时把我在实际操作中踩过的坑和总结的技巧一并分享出来。整个流程基于常见的工程实践补充细节你照着做基本能复现。2. 环境准备与依赖安装的完整流程2.1 系统环境与基础依赖我用的环境是Ubuntu 18.04这是ORB-SLAM2社区里兼容性最好的版本之一。Ubuntu 20.04也能跑但Pangolin和OpenCV的版本匹配会稍微麻烦一点。如果你用的是更新的系统建议直接用Docker起一个18.04的容器省去大量依赖冲突的排查时间。基础依赖包括编译工具链、CMake、Git这些常规工具以及ORB-SLAM2强依赖的几个库OpenCV、Eigen3、Pangolin、DBoW2和g2o。后两个其实已经包含在ORB-SLAM2的第三方目录里不需要单独安装但OpenCV、Eigen3和Pangolin必须提前装好。sudo apt update sudo apt install -y build-essential cmake git libgtk2.0-dev pkg-config \ libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \ libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev上面这串是OpenCV编译前需要的基础库。很多人装OpenCV时只装主包结果编译到一半报缺少某个codec回头再补很浪费时间。2.2 OpenCV版本选择与安装ORB-SLAM2官方推荐OpenCV 3.4.x系列我用的是3.4.16。为什么不建议用OpenCV 4.x因为ORB-SLAM2源码里有一些API在4.x里被移除了比如CV_LOAD_IMAGE_UNCHANGED这种常量虽然可以手动改但改动点比较分散容易漏。如果你非要用4.x记得把源码里所有旧常量替换成新的枚举名。编译OpenCV的时候有几个CMake选项值得注意cmake -D CMAKE_BUILD_TYPERelease \ -D CMAKE_INSTALL_PREFIX/usr/local \ -D WITH_CUDAOFF \ -D BUILD_EXAMPLESOFF \ -D BUILD_opencv_python2OFF \ -D BUILD_opencv_python3OFF \ ..关掉CUDA是因为ORB-SLAM2本身不用GPU加速开了反而增加编译时间和依赖复杂度。关掉Python绑定和示例能省不少编译时间。make -j4根据你机器的核数调整内存小于8G的话建议用-j2否则容易在链接阶段被OOM killer干掉。注意OpenCV安装完成后一定要执行sudo ldconfig刷新动态链接库缓存否则编译ORB-SLAM2时可能报找不到so文件。2.3 Eigen3与Pangolin的安装要点Eigen3直接用apt装就行版本3.3以上都可以sudo apt install -y libeigen3-devPangolin是ORB-SLAM2的可视化依赖负责显示特征点、轨迹和地图点。它依赖GLEW、GLU和Python。安装Pangolin时最容易出问题的是它自带的libpng和系统库冲突如果编译报错可以在CMake里加上-DBUILD_EXAMPLESOFF跳过示例编译。Pangolin的版本也有讲究。v0.5和v0.6在API上有细微差别ORB-SLAM2的源码对v0.5兼容性更好。如果你用v0.6可能会遇到glGenVertexArrays相关的编译错误需要在CMakeLists里显式链接GL库。2.4 ORB-SLAM2源码编译与常见报错从官方仓库克隆源码后先别急着./build.sh。我建议手动分步编译这样出错时能定位到具体模块cd ORB_SLAM2 chmod x build.sh ./build.shbuild.sh会依次编译DBoW2、g2o和ORB-SLAM2主库。常见的报错有三类一是找不到Eigen通常是/usr/include/eigen3路径没被CMake识别可以在CMakeLists里加include_directories(/usr/include/eigen3)二是Pangolin链接失败检查/usr/local/lib下是否有libpango*.so三是C标准问题ORB-SLAM2用的是C11如果你的编译器默认C14以上某些旧写法会报警告但不影响编译。编译完成后lib/libORB_SLAM2.so和各个可执行文件应该都生成了。这时候先别跑EuRoC用TUM数据集快速验证一下环境是否正常能省去后面排查环境问题的时间。3. EuRoC数据集的结构与使用方式3.1 数据集目录结构解析EuRoC数据集每个序列比如MH_01_easy、V1_01_easy下载解压后目录结构是这样的MH_01_easy/ ├── cam0/ │ └── data/ │ ├── 1403636579763555584.png │ └── ... ├── cam1/ │ └── data/ │ └── ... ├── imu0/ │ └── data.csv ├── state_groundtruth_estimate0/ │ └── data.csv └── sensor.yamlcam0和cam1分别是左右目相机的图像序列文件名是纳秒级时间戳。imu0里是200Hz的IMU数据state_groundtruth_estimate0里是运动捕捉系统给出的真值位姿。sensor.yaml里记录了相机内参、畸变系数、双目基线、IMU噪声参数等关键信息。ORB-SLAM2的双目模式需要的是左右目图像的时间戳对齐。EuRoC的cam0和cam1图像是硬件同步的时间戳基本一致但偶尔会有几纳秒的偏差。ORB-SLAM2内部用时间戳做关联如果偏差太大可能导致某帧匹配不上所以建议在读取时做一次时间戳对齐检查。3.2 相机参数提取与配置文件编写ORB-SLAM2的双目配置文件格式是YAML需要包含相机内参、畸变系数、双目基线、图像尺寸等信息。EuRoC的sensor.yaml里给的是原始参数但ORB-SLAM2需要的格式不太一样需要手动转换。以MH_01_easy为例cam0的内参是Camera.fx: 458.654 Camera.fy: 457.296 Camera.cx: 367.215 Camera.cy: 248.375 Camera.k1: -0.28340811 Camera.k2: 0.07395907 Camera.p1: 0.00019359 Camera.p2: 1.76187114e-05 Camera.width: 752 Camera.height: 480 Camera.fps: 20.0 Camera.bf: 47.90639384423901这里的Camera.bf是基线乘以焦距EuRoC的基线大约是0.11米焦距458.654乘起来约50.45。但sensor.yaml里给的bf是47.9这是因为实际标定时的焦距略有差异。建议直接用sensor.yaml里的值不要自己算。提示Camera.fps在双目模式下其实不影响运行ORB-SLAM2是按时间戳处理帧的但填20.0是EuRoC的实际采集频率保持一致性比较好。3.3 图像序列的读取与时间戳处理ORB-SLAM2的双目示例程序stereo_euroc已经写好了EuRoC的读取逻辑但它的读取方式比较粗暴把cam0和cam1的图像路径分别存成两个vector然后按索引一一对应。这种方式假设左右目图像数量完全一致且时间戳严格对齐。实际上EuRoC大部分序列满足这个条件但V2_03这种序列偶尔会有丢帧。如果你要自己写读取逻辑建议用时间戳做关联而不是索引。具体做法是先读cam0的所有时间戳再读cam1的所有时间戳然后用双指针法找最近邻匹配。匹配阈值设成1毫秒以内超过这个阈值的帧直接丢弃。这样能避免因为丢帧导致的左右目错位。另外EuRoC的图像是灰度图ORB-SLAM2的双目模式默认就是处理灰度图所以不需要做颜色空间转换。如果你用的是其他数据集记得在读取时用cv::IMREAD_GRAYSCALE。4. 双目ORB-SLAM2的核心配置与代码修改4.1 配置文件的关键参数详解ORB-SLAM2的双目配置文件里除了相机内参还有几个影响性能的关键参数参数名含义推荐值调整影响ORBextractor.nFeatures每帧提取的特征点数1200增大提升精度但降低帧率ORBextractor.scaleFactor金字塔缩放因子1.2减小增加尺度覆盖但增加计算量ORBextractor.nLevels金字塔层数8增大提升大尺度变化鲁棒性ORBextractor.iniThFAST初始FAST阈值20降低增加特征点但引入噪声ORBextractor.minThFAST最小FAST阈值7同上用于补充特征Viewer.KeyFrameSize关键帧显示尺寸0.05仅影响可视化Viewer.ViewpointX/Y/Z视角位置根据场景调整仅影响可视化对于EuRoC这种室内场景纹理比较丰富但运动比较剧烈我建议把nFeatures设成1500nLevels保持8iniThFAST设成20。如果发现跟踪丢失频繁可以把iniThFAST降到15但要注意特征点多了之后后端优化会变慢。4.2 双目匹配与深度计算的关键代码ORB-SLAM2的双目匹配在Frame.cc里的ComputeStereoMatches函数中实现。它的核心逻辑是对左目每个特征点在右目图像上沿极线搜索匹配点然后用三角化计算深度。关键步骤包括对左目特征点按行分组因为双目校正后极线是水平的同一行的特征点才可能匹配。对每个左目特征点在右目对应行的[minU, maxU]范围内搜索ORB描述子最相似的点。用SADSum of Absolute Differences做粗匹配再用描述子距离做精匹配。对匹配成功的点做抛物线拟合得到亚像素级的视差。用z fx * bf / disparity计算深度其中bf是基线乘焦距。这里有个细节minU和maxU的计算依赖于bf和最小/最大深度阈值。ORB-SLAM2默认的最小深度是0最大深度是bf即视差为1时的深度。对于EuRoC基线0.11米焦距458最大深度约50米室内场景完全够用。如果你发现深度图里有很多噪点可以检查ComputeStereoMatches里的thOrbDist阈值。默认是0.7调小到0.6能过滤掉一些误匹配但会减少有效深度点数量。4.3 需要修改的源码点与编译选项跑EuRoC双目官方示例stereo_euroc基本可以直接用但有几个地方建议改一下第一Examples/Stereo/stereo_euroc.cc里的LoadImages函数用的是cv::imread默认读彩色图。EuRoC是灰度图虽然读彩色再转灰度也能跑但多了一次转换。改成cv::IMREAD_GRAYSCALE能省一点时间。第二示例里的时间戳读取用的是std::stod对于EuRoC的纳秒时间戳double精度可能不够。建议改成std::stoll读成long long再除以1e9转成秒。不过ORB-SLAM2内部用的是double存时间戳所以这个改动主要是为了避免读取时的精度损失。第三如果你要跑所有EuRoC序列做批量测试建议把示例程序改成接受命令行参数指定序列路径而不是硬编码。这样能省去反复改代码的麻烦。编译时确保CMakeLists.txt里链接了正确的OpenCV版本。如果系统里有多个OpenCV用find_package(OpenCV 3.4 REQUIRED)指定版本号。5. 完整运行流程与实操记录5.1 单序列运行的完整命令假设你已经编译好了ORB-SLAM2EuRoC数据集放在~/datasets/EuRoC/MH_01_easy配置文件放在ORB_SLAM2/Examples/Stereo/EuRoC.yaml词袋文件用ORBvoc.txt运行命令是./Examples/Stereo/stereo_euroc \ Vocabulary/ORBvoc.txt \ Examples/Stereo/EuRoC.yaml \ ~/datasets/EuRoC/MH_01_easy \ Examples/Stereo/EuRoC_TimeStamps/MH01.txt最后一个参数是时间戳文件ORB-SLAM2用它来关联左右目图像。这个文件需要自己生成格式是每行一个时间戳秒为单位对应cam0的图像文件名。生成脚本可以用Python写import os import glob cam0_path os.path.expanduser(~/datasets/EuRoC/MH_01_easy/cam0/data) timestamps sorted([os.path.splitext(f)[0] for f in os.listdir(cam0_path)]) with open(MH01.txt, w) as f: for ts in timestamps: f.write(f{int(ts)/1e9:.9f}\n)注意时间戳要转成秒并保留足够的小数位否则关联时会丢精度。5.2 运行过程中的可视化观察程序启动后Pangolin窗口会显示几个视图左上角是当前帧的特征点跟踪情况右上角是地图点和关键帧下方是轨迹。双目模式下你还能看到左右目的匹配点连线。运行MH_01_easy时我观察到几个现象前几帧初始化时地图点比较少轨迹会有轻微抖动随着关键帧增加地图点迅速增多轨迹逐渐平滑回环检测触发时整个地图会做一次全局优化轨迹会有明显修正。如果Pangolin窗口卡顿可以在配置文件里把Viewer.KeyFrameSize调小或者直接关掉可视化把Viewer相关的参数注释掉用SaveTrajectoryEuRoC保存轨迹后离线分析。5.3 轨迹保存与精度评估方法ORB-SLAM2运行结束后会保存两个轨迹文件CameraTrajectory.txt和KeyFrameTrajectory.txt。前者是每帧的位姿后者是关键帧的位姿。评估精度时通常用evo工具对比真值轨迹。pip install evo evo_traj tum CameraTrajectory.txt --refMH01_groundtruth.txt -p --plot_modexyz evo_ape tum MH01_groundtruth.txt CameraTrajectory.txt -va --plotevo_ape会输出ATEAbsolute Trajectory Error的RMSE、均值、中位数等指标。MH_01_easy上调好参数的ORB-SLAM2双目模式ATE通常在0.05米左右V1_01_easy因为运动更剧烈ATE会稍大一些。注意EuRoC的真值轨迹和ORB-SLAM2的坐标系可能不一致评估前需要做对齐。evo的--align选项可以自动做Sim3对齐但如果你要严格评估尺度应该用--align --correct_scale。6. 常见问题与排查技巧实录6.1 跟踪丢失与初始化失败跟踪丢失是双目ORB-SLAM2最常见的问题。表现是Pangolin窗口里特征点突然变少轨迹断裂终端输出Track lost。原因通常有三类一是图像纹理不足比如对着白墙二是运动过快导致帧间重叠区域太小三是双目匹配失败深度点太少。排查时先看终端输出的特征点数量。如果每帧特征点少于100说明ORB提取有问题检查iniThFAST和nFeatures。如果特征点够但深度点少检查双目匹配的thOrbDist和bf参数。如果是运动过快可以降低图像播放速率或者用IMU数据做预积分辅助需要额外改代码。6.2 轨迹漂移与尺度不一致双目SLAM理论上尺度是确定的因为基线提供了绝对尺度。但如果标定参数不准尺度会有偏差。EuRoC的标定参数比较准一般不会出问题。如果你发现轨迹整体缩放不对检查Camera.bf是否填错。bf是基线乘焦距单位是米乘像素填成厘米或毫米会导致尺度差几个数量级。漂移则主要来自累积误差。ORB-SLAM2有回环检测和全局BA能修正大部分漂移。如果漂移仍然明显检查回环检测是否触发。可以在配置文件里把LoopClosing相关的参数调激进一些比如降低minScore阈值。6.3 编译与运行时的典型报错速查报错信息可能原因解决方法undefined reference to cv::...OpenCV版本不匹配检查CMakeLists里的OpenCV版本cannot find -lpangoPangolin未安装或路径不对重新安装Pangolin并ldconfigSegmentation faultat startup配置文件路径错误检查YAML文件路径和格式Track lostimmediately时间戳文件格式错误检查时间戳是否为秒且精度足够Killedduring build内存不足减少make的-j参数No images found数据集路径错误检查路径是否指向序列根目录6.4 提升运行效率的实用技巧EuRoC一个序列有几千帧跑完一遍要十几分钟。如果想快速验证可以只跑前500帧在时间戳文件里截取前500行即可。另外关掉Pangolin可视化能提升约20%的速度因为可视化渲染占了不少CPU。如果要做批量测试建议写一个shell脚本遍历所有序列每个序列跑完后自动用evo评估并记录结果。这样能省去大量手动操作。7. 参数调优与性能提升的进阶思路7.1 特征点数量与跟踪精度的平衡nFeatures是最直接影响性能的参数。设成1000时帧率能到30fps以上但跟踪精度一般设成2000时精度提升但帧率降到15fps左右。对于EuRoC这种20Hz采集的数据集帧率只要不低于20fps就不会丢帧。我建议设成1500在精度和速度之间取平衡。另外scaleFactor和nLevels影响的是尺度不变性。EuRoC的飞行器运动比较剧烈尺度变化大nLevels设成8是合理的。如果你跑的是手持设备的数据运动平缓可以降到6。7.2 双目匹配阈值对深度图的影响thOrbDist控制双目匹配的严格程度。默认0.7调低到0.6能减少误匹配但深度点会变少。调高到0.8会增加深度点但可能引入错误深度。我的经验是纹理丰富的场景用0.7纹理弱的场景用0.6。还有一个隐藏参数是minDepth和maxDepth在Frame.cc里硬编码。默认minDepth0maxDepthbf。对于EuRoCmaxDepth约50米室内场景够用。如果你跑室外数据需要把maxDepth调大否则远处点会被丢弃。7.3 回环检测与全局优化的触发条件ORB-SLAM2的回环检测基于DBoW2词袋模型触发条件是当前关键帧和候选关键帧的相似度超过阈值。EuRoC的室内场景回环比较多MH_01_easy里飞行器绕了一圈回到起点回环检测能明显修正轨迹。如果回环没触发检查LoopClosing里的minScore。默认是0.015可以降到0.01。但降太低会引入误回环导致地图错乱。另一个方法是增加关键帧的密度让回环候选更多。8. 我在实际调试中的几点体会跑通EuRoC双目ORB-SLAM2这件事说难不难说简单也不简单。环境配置是最耗时的部分尤其是OpenCV和Pangolin的版本匹配我前后重装了三次才找到稳定的组合。建议新手直接用Docker能省掉大量依赖排查的时间。参数调优方面不要一上来就改代码。先把默认参数跑一遍看看基线效果再针对具体问题调整。我见过有人把nFeatures设成5000结果帧率掉到5fps反而更容易丢跟踪。最后分享一个小技巧如果你要对比不同参数的效果建议用同一个序列的前500帧做快速测试不要每次都跑完整序列。这样一轮测试只要两三分钟调参效率能提升好几倍。等参数稳定了再跑完整序列做最终评估。