如果你最近在Ubuntu上折腾视觉SLAM,那ORB-SLAM1/2/3这套经典开源项目,大概率是你绕不开的第一站。这个系列覆盖了单目、双目、RGB-D,再到后期加入IMU紧耦合,几乎就是一部“特征点SLAM进化史”。但说实话,它的源码下载下来,很多新手第一关不是算法,而是编译环境。OpenCV版本、Pangolin版本、GCC版本、Eigen路径,随便一个不对,报错就能让你耗上一整天。
我写这篇指南的目的很明确:在Ubuntu环境下,把ORB-SLAM1/2/3从头到尾复现跑通。不是那种“复制粘贴命令然后祈祷成功”的教程,而是把版本选择、依赖原理、编译顺序、运行参数这些关键点讲透。适合刚接触SLAM、想在本地把经典算法跑起来的新手,也适合那些已经编译过但被各种兼容问题折磨过的人对照排查。
1. 先搞清楚三个版本再动手
1.1 三个版本的核心差异对比
ORB-SLAM1、2、3三个版本表面上目录结构很像,都是Thirdparty加Examples加Vocabulary,但实际上差别非常大。如果不看版本差异直接拿同一个思路去编译运行,很容易被一些“奇怪”的问题绕进去。
| 对比项 | ORB-SLAM1 | ORB-SLAM2 | ORB-SLAM3 |
|---|---|---|---|
| 开源时间 | 2015年 | 2017年 | 2021年 |
| 支持传感器 | 单目 | 单目、双目、RGB-D | 单目、双目、RGB-D,单目+IMU、双目+IMU |
| 核心亮点 | 建立了整套基于ORB特征的SLAM框架 | 加入双目标定复用与RGB-D,鲁棒性明显提升 | 多地图系统Atlas、IMU紧耦合、鱼眼相机模型 |
| 典型数据集 | TUM | TUM、KITTI、EuRoC | EuRoC、TUM-VI、KITTI |
| 编译依赖复杂度 | 较低 | 中等 | 较高,额外需要Sophus |
| 源码体量 | 紧凑,适合学习 | 工程化完善,资料最多 | 代码量大,算法细节多 |
ORB-SLAM1是单目SLAM的集大成者,它提出了一套非常完整的思路:用ORB特征做前端跟踪,用词袋模型做回环检测,用图优化做全局一致性的修正。整套代码结构清晰,是很多人入门视觉SLAM的第一份源码。
ORB-SLAM2则在1的基础上做了大量工程化的扩展,最大变化是支持了双目和RGB-D相机输入。它不再只依赖单目三角化恢复深度,而是可以主动利用传感器提供的深度信息,因此初始化更快,尺度也更稳定。
ORB-SLAM3是一次大重构,加入了很多新东西:IMU和视觉的紧耦合、Atlas多地图系统、鱼眼相机模型,甚至将单目、双目、RGB-D、视觉惯性这些传感器统一到了一个框架里。功能是强大了,但代码复杂度也上了一个台阶。
1.2 新手到底应该先编译哪个版本
很多人一上来就问“我该从哪个版本开始”,我的建议非常直接:如果只是想跑通一次完整的SLAM流程,先做ORB-SLAM2;如果想深入学习单目SLAM的原始框架,那就从ORB-SLAM1开始;如果你的目标明确是视觉惯性导航VIO方向,直接上ORB-SLAM3,不要犹豫。
ORB-SLAM2是最好的“入门版本”,理由有三点:第一,它对传感器的包容度高,单目、双目、RGB-D都能跑,方便你横向对比不同输入的区别;第二,网络上关于它的教程、问答、避坑经验最多,遇到问题基本都能搜到答案;第三,它的运行效果直观,Pangolin界面里可以同时看到当前帧、关键帧、地图点和轨迹,很适合建立对整个系统的感性认识。
至于硬件需求,这里要辟个谣:ORB-SLAM系列并不是非要有NVIDIA显卡才能跑。它主要靠CPU做特征提取和优化,Pangolin只是用OpenGL做可视化和渲染。所以一台普通的四核CPU、8GB内存的电脑就够了。硬盘尽量预留20GB以上,因为TUM、KITTI、EuRoC这些数据集动辄几个GB,下载解压都需要空间。
2. Ubuntu环境准备与依赖逐个击破
2.1 系统版本和基础工具怎么选
Ubuntu版本选择这件事,直接影响你后面要踩多少个坑。我分别说下三个主流版本的情况:
- Ubuntu 18.04:默认OpenCV 3.2、GCC 7,这三个ORB-SLAM版本在它上面编译最省心,基本不需要改源码。缺点是系统本身已经比较老了,软件源可能存在问题。
- Ubuntu 20.04:默认OpenCV 4.2、GCC 9,这是目前最均衡的选择。编译ORB-SLAM2和ORB-SLAM3都很顺利,ORB-SLAM1需要改几个兼容性宏。
- Ubuntu 22.04:默认OpenCV 4.5+、GCC 11,这时候就要小心了。GCC 11对C++标准检查更严格,ORB-SLAM系列里很多文件没有显式包含
unistd.h,编译会报usleep未定义错误,需要手动补头文件。
我个人最推荐20.04。如果是虚拟机或者双系统,先装好基础工具:
sudo apt update sudo apt install -y git cmake g++ build-essentialbuild-essential这个包一定要装,它一次性打包了GCC、G++、make等编译链核心工具。如果缺了这个,后面任何源码编译都会在第一步直接失败。
2.2 核心依赖安装实操
编译ORB-SLAM系列需要四个核心依赖:Eigen、OpenCV、Pangolin,以及各个版本自带的第三方库(ORB-SLAM1/2需要的DBoW2、g2o,ORB-SLAM3额外需要的Sophus)。其中前三个需要你自己提前装好。
先装Eigen。这是一个头文件库,专门用于矩阵运算,在SLAM里几乎所有坐标系变换、优化求解都离不开它。直接通过apt装最简单的版本即可:
sudo apt install -y libeigen3-dev装完以后头文件在/usr/include/eigen3下,CMake通常会自己找到。需要注意的是,Eigen不需要编译,它只是头文件,所以安装速度非常快。
然后是OpenCV。这里有一个很典型的坑:用apt还是源码编译?我的建议是新手一律用apt:
sudo apt install -y libopencv-devUbuntu 20.04默认会给OpenCV 4.2,这个版本对ORB-SLAM2和3完全够用。自己从源码编译OpenCV虽然能拿到更新版本,但编译过程非常耗时,还需要解决一堆Python绑定、FFmpeg依赖问题,投入产出比太低。等到你把ORB-SLAM跑通了,再考虑要不要折腾OpenCV版本也不迟。
最后是Pangolin。这是ORB-SLAM用来画界面、显示轨迹的GUI库,它的版本选择至关重要。我强烈建议你克隆Pangolin源码后,手动切到v0.5分支再编译:
sudo apt install -y libglew-dev libboost-dev libboost-thread-dev libboost-filesystem-dev libpython3-dev ffmpeg git clone <Pangolin仓库地址> cd Pangolin git checkout v0.5 mkdir build && cd build cmake .. make -j4 sudo make install为什么要切到v0.5?因为ORB-SLAM1/2的源码是2015到2017年写的,里面大量使用了旧版Pangolin的API。Pangolin新版本改动很大,很多头文件路径和函数接口都变了,直接用新版本编译会报一堆错。v0.5虽然老,但和ORB-SLAM全系列的兼容性是最好的。
2.3 编译前的环境验证清单
每次帮人排查编译问题,我都发现很多报错其实在编译前就能避免。所以强烈建议在动手编译ORB-SLAM之前,先花三分钟做一个环境自检:
cmake --version gcc --version pkg-config --modversion opencv4 ls /usr/include/eigen3/Eigen ls /usr/local/include/pangolin如果pkg-config --modversion opencv4返回了版本号,说明OpenCV装好了;如果提示找不到opencv4,那就用pkg-config --modversion opencv试试,Ubuntu 18.04上OpenCV 3.2的pkg-config名字就是opencv。Pangolin则直接看/usr/local/include/pangolin目录存不存在,存在就没问题。
这个验证清单能帮你把问题定位到“依赖缺失”还是“代码本身不兼容”,省下很多瞎折腾的时间。我就是因为一开始跳过这步,后面花了大半天才查出来是Pangolin版本太新导致ORB-SLAM2编译失败。
3. 三个版本的编译与运行实操
3.1 ORB-SLAM1编译与单目数据集运行
先从ORB-SLAM1开始。把源码克隆下来之后,先看目录结构:Thirdparty里面放着DBoW2和g2o,Vocabulary里面是ORB词袋文件,Examples下面是各个传感器的示例程序。整个项目是依靠根目录下的build.sh一键编译的,它会依次编译DBoW2、g2o,最后编译ORB-SLAM1本体。
cd ORB_SLAM1 ./build.sh等待编译完成后,下载一个TUM数据集。TUM数据集的压缩包解压后会得到类似rgbd_dataset_freiburg1_room这样的目录,里面包含rgb和depth两个子目录。对ORB-SLAM1来说,单目模式只需要rgb下面的彩色图序列。运行命令如下:
cd Examples/Monocular ./mono_tum ../../Vocabulary/ORBvoc.txt TUM1.yaml /path/to/rgbd_dataset_freiburg1_room第一个参数是词袋文件路径,第二个是相机参数文件,第三个是数据集根目录,注意路径要写对,否则程序不会报错,而是直接卡在“等待图像”状态。
如果你用的是Ubuntu 20.04及以上系统、通过apt安装了OpenCV 4,那ORB-SLAM1大概率会报编译错误,主要集中在几个OpenCV旧版宏失效的问题上。最常见的是CV_LOAD_IMAGE_UNCHANGED未声明,需要手动把它改成cv::IMREAD_UNCHANGED。另一个常见问题是CV_RGB2GRAY未声明,要改成cv::COLOR_RGB2GRAY。这些宏在OpenCV 3中还存在,到OpenCV 4就被彻底移除了。
3.2 ORB-SLAM2编译与三种传感器运行示例
ORB-SLAM2是覆盖面最广的版本,它的编译同样是一键脚本:
cd ORB_SLAM2 ./build.sh编译完成之后,你可以体验三种不同传感器的运行流程。首先是单目TUM,命令和ORB-SLAM1几乎一样:
./Examples/Monocular/mono_tum Vocabulary/ORBvoc.txt Examples/Monocular/TUM1.yaml /path/to/fr1_room其次是双目KITTI。KITTI数据集是自动驾驶场景,图像分辨率大,特征点分布密集,对硬件要求也更高。运行前需要先下载KITTI的00序列,解压后目录里是一系列PNG图像。命令如下:
./Examples/Stereo/stereo_kitti Vocabulary/ORBvoc.txt Examples/Stereo/KITTI00-02.yaml /path/to/KITTI/00最后是RGB-D TUM。这一步最容易出问题,因为RGB-D模式要求你额外提供一个“关联文件”,也就是associations.txt。这个文件的作用是把每一帧RGB图像和它对应的深度图在时间戳上对齐。TUM数据集官方提供了一对关联脚本,如果你下载的数据集目录里有rgb.txt和depth.txt,可以用这个命令生成:
python associate.py rgb.txt depth.txt > associations.txt然后把关联文件作为第四个参数传给程序:
./Examples/RGB-D/rgbd_tum Vocabulary/ORBvoc.txt Examples/RGB-D/TUM1.yaml /path/to/fr1_room /path/to/associations.txt我还想给新手一个建议:ORB-SLAM2的源码里包含ROS接口,但你在首次复现时千万不要去碰ROS版。ROS的编译依赖、工作空间环境变量、还有与Pangolin窗口多线程的冲突,会把你绕到云里雾里。先把非ROS版跑通,理解整个流程,再考虑扩展。
3.3 ORB-SLAM3编译与EuRoC数据集运行
ORB-SLAM3是所有版本里最复杂的,也是最值得精心准备的。除了之前提到的Eigen、OpenCV、Pangolin之外,它还需要Sophus,这是一个用于李群李代数运算的库。好消息是,ORB-SLAM3已经在Thirdparty/Sophus里内置了一份特定版本,你不需要额外从系统安装,编译时它会随着build.sh一起完成。
cd ORB_SLAM3 ./build.sh如果是在Ubuntu 22.04上编译,建议先给ORB-SLAM3的源代码打一个补丁:在src目录下各.cc文件的头文件区域统一加上#include <unistd.h>,否则GCC 11会在编译后期报出大量usleep未定义错误,而且这个报错不是一次性出现在一个文件里的,是散落在多个编译单元中,逐个修改会非常烦人。
ORB-SLAM3最常见的运行示例是EuRoC数据集,这是一个无人机采集的双目+IMU数据。下载MH_01序列,解压后你会看到类似mav0的目录结构,里面包含cam0、cam1、imu0等子目录。运行双目模式:
./Examples/Stereo/stereo_euroc Vocabulary/ORBvoc.txt Examples/Stereo/EuRoC.yaml /path/to/MH_01 Examples/Stereo/EuRoC_TimeStamps/MH01.txt这里第三个参数要指向包含mav0的上一级目录,第四个参数是时间戳文件,源码里已经提供好了。如果你想体验视觉惯性融合,可以运行单目+IMU版本:
./Examples/Monocular-Inertial/mono_inertial_euroc Vocabulary/ORBvoc.txt Examples/Monocular-Inertial/EuRoC.yaml /path/to/MH_01 Examples/Monocular-Inertial/EuRoC_TimeStamps/MH01.txt dataset-MH_01_mono_inertial3.4 运行效果验证与轨迹评估
当你成功启动程序后,屏幕上会出现一个Pangolin窗口,里面能看到相机当前帧、特征点、共视关键帧以及全局地图点云。终端也会实时打印状态信息和处理帧率。以TUM fr1数据集为例,正常运行时帧率大概在20到40 FPS之间,如果只有个位数,就要检查是不是后台跑了很多东西,或者数据集精度太高导致特征提取耗时过长。
单目模式运行时有一个细节:程序一开始会显示“waiting for initialization”或者类似状态,这是正常的,因为单目SLAM需要等相机发生足够的平移运动,才能通过三角化恢复出初始地图。第一帧到第二帧之间如果相机几乎没动,初始化就一直无法完成。所以跑数据集时,看到程序“停住”别急着杀进程,给它几秒钟观察相机运动。
程序运行完会自动退出,并在当前目录生成KeyFrameTrajectory.txt和CameraTrajectory.txt。想评估精度的话,可以用evo工具和数据集真值做对比:
pip install evo evo_ape tum KeyFrameTrajectory.txt groundtruth.txt -a -pTUM数据集的真值文件就是目录里的groundtruth.txt,EuRoC则可以使用state_groundtruth_estimate0下的数据。-a表示自动对齐,-p表示绘制曲线。
4. 常见报错与排查实录
4.1 高频编译错误速查表
根据我接触过的案例,ORB-SLAM系列编译报错其实就那么几类。我整理了一张速查表,你可以对照排查:
| 现象 | 根因 | 解决方案 |
|---|---|---|
编译时提示Eigen/Dense: No such file | Eigen未安装或路径不对 | 执行sudo apt install libeigen3-dev,确认/usr/include/eigen3存在 |
编译时提示usleep was not declared | GCC 11及以上版本对头文件检查更严格 | 在所有src/*.cc中加入#include <unistd.h> |
提示CV_LOAD_IMAGE_UNCHANGED未声明 | OpenCV 4移除了旧版图像加载宏 | 全局替换为cv::IMREAD_UNCHANGED |
提示CV_RGB2GRAY未声明 | OpenCV 4改用新的颜色空间常量 | 全局替换为cv::COLOR_RGB2GRAY |
| Pangolin相关头文件找不到或API冲突 | Pangolin版本过新,与旧代码不兼容 | 切换到Pangolin v0.5分支重新编译安装 |
链接阶段报错找不到libopencv_core.so | OpenCV编译安装与CMake配置不一致 | 用pkg-config --modversion opencv4验证,删除build目录后重新cmake |
| 编译过程中内存不足直接卡死 | 并行编译任务过多 | 将make -j8改为make -j4或更小 |
最后一条其实很关键。很多人拿到源码后习惯性地make -j8,如果内存只有8GB,编译过程和Pangolin、OpenCV这种大库同时启动,很容易打到OOM。不要贪并行数,-j4在大多数机器上是最稳妥的。
4.2 运行阶段的典型问题
编译过了,不代表运行就一帆风顺。第一次把ORB-SLAM2跑起来时,我遇到的第一个问题是Pangolin窗口完全不显示。后来发现是因为我通过SSH远程连到机器上执行程序,没有图形显示环境。解决办法是在有桌面的系统上直接运行,或者用虚拟机的图形界面。远程环境想显示窗口,需要配置X11转发,但新手阶段不建议折腾这个。
第二个典型的运行问题是一启动就Segmentation fault。这种崩溃九成九是参数路径写错了。程序对数据集路径、YAML文件路径、关联文件路径都是直接读取,不会做稳健性检查,路径一旦失效就会在读取图像时直接访问非法内存。解决方法是仔细核对四个参数的路径,尤其是关联文件,RGB-D模式少了它几乎必崩。
第三个是RGB-D模式下轨迹错乱、重影严重。这种情况通常是关联文件时间戳对齐精度不够。TUM的associate.py脚本默认的匹配容差是0.02秒,如果数据集本身时间戳漂移较大,可以尝试把容差放宽一点,但不要超过0.05秒,否则会引入大量的错误匹配。
4.3 运行效果调优的几个方向
跑通只是第一步,把效果调好才是真正有价值的部分。我自己在调参过程中总结了几条经验:
第一,不要盲目追求高帧率。有些新手看到帧率偏低就在YAML文件里猛降特征点数量,结果地图质量直线下降。ORB-SLAM系列的基础是ORB特征,特征太少会导致跟踪丢失。如果你觉得CPU扛不住,优先检查系统负载,而不是一上来就砍特征。
第二,想纯粹测试算法而不需要可视化,可以在源码里关闭Viewer线程。ORB-SLAM的Viewer线程负责渲染和GUI交互,它会占据不少CPU资源。跑批量实验时,直接在System.cc里把mbUseViewer设成false,或者不启动mpViewer,能显著提升处理速度。
第三,YAML相机参数文件里有一个ORBextractor.nFeatures参数,控制每帧提取的特征点数量,默认通常是1000到1500。对于纹理稀疏的场景,这个值可以提高到2000,对于纹理丰富的高速运动场景,反而建议降低到800左右并加快特征提取阈值,这样能减少计算量并保持跟踪稳定性。
第四,EuRoC这类视觉惯性数据集,IMU参数不能随便改。如果你用的不是官方提供的相机参数而是自己的设备,必须先完成IMU标定,包括噪声密度和随机游走,否则单目+IMU模式的轨迹会很快发散。新手跑官方数据集时,尽量保持YAML原样。
写在最后的一点经验
把ORB-SLAM1/2/3都复现一遍之后,我最大的感受是:这套代码对新手真正的门槛不在算法,而在环境。很多人一开始都以为是自己代码写得不好、调试能力不行,反复重装系统,最后发现就是某个依赖版本不匹配。
所以再提醒一句:动工之前,一定先做环境验证清单,并且把你装的所有依赖版本记录下来。哪天突然编译报错,至少能判断是不是自己不小心升级了OpenCV或者Pangolin。另外,三个版本最好放在不同目录,各自使用独立的build文件夹,不要图省事共用第三方库的编译产物。
最后分享一个小技巧:把常用的运行命令写成一个shell脚本保存下来,数据集路径、词表路径、YAML路径都用绝对路径。这样每次复现只需要执行一行命令,既减少手误,也方便以后给别人做演示。希望这篇指南能帮你少走弯路,顺利跑出自己的第一条SLAM轨迹。