做视觉SLAM的同学,十有八九都绕不开ORB-SLAM3这个名字,而Euroc数据集基本算得上是跑SLAM算法绕不开的“标准考卷”。刚接触ORB-SLAM3那会儿,我一度以为下载源码、编个build.sh就能顺利跑出轨迹,结果光是在环境配置和数据准备上就折腾了两天。这期间踩过的坑、搜过的帖子、翻过的Issue,汇总起来其实比官方Readme里写的那几行命令值钱得多。
这篇文章就围绕“ORB-SLAM3的Euroc数据集测试”这条主线,把从源码准备、依赖安装、数据集下载,到单目、双目、双目惯性三种模式跑通,再到用evo评估精度的完整流程,全部拆开揉碎讲一遍。不管你是刚入门的SLAM萌新,还是想快速用ORB-SLAM3做对比实验的研究党,都能从这里找到可以直接照抄的操作步骤和避坑方案。
1. 项目解读:为什么用ORB-SLAM3跑Euroc是入门必修课
1.1 ORB-SLAM3到底是个什么东西
ORB-SLAM3是西班牙萨拉戈萨大学(University of Zaragoza)的Tardos团队在2020年前后开源的一套视觉SLAM系统。它最大的特点是一个系统通吃单目、双目、RGB-D三种传感器模式,并且可以无缝切换视觉与视觉惯性(VI)两种工作方式。相比ORB-SLAM2,它加入了基于多子地图(Multi-Map)的视觉惯性紧耦合、基于最大后验概率(MAP)的IMU初始化,以及场景重识别和后端图优化的全套闭环机制。
通俗点讲,ORB-SLAM2更像是一个只能帮你在“连续运动”中定位建图的工具,一旦跟踪丢失就得重新来;ORB-SLAM3则多了一套“记忆”系统,能识别出之前来过的地方,并把多个子地图合并成一个完整轨迹。这个特性在多楼层、往返运动、长时间大范围场景里,优势非常明显。也正因为这套架构的通用性强,ORB-SLAM3在学术界和工业界都被广泛用来做算法对比的baseline。
1.2 为什么偏偏选Euroc数据集来验证
Euroc数据集(EuRoC MAV Dataset)是苏黎世联邦理工(ETH)发布的一组无人机(MAV)视觉惯性数据集,采集设备是双目相机加MEMS IMU,场景是室内厂房和室外小范围环境。它提供同步好的双目图像流、IMU采样数据,还有运动捕捉系统提供的6自由度真值轨迹(ground truth)。对于SLAM算法评测来说,它有三个不可替代的优势。
一是传感器配置主流,双目加IMU恰好匹配ORB-SLAM3最引以为傲的视觉惯性紧耦合能力。二是数据采集时包含了快速旋转、剧烈抖动、光照变化、低纹理墙面等真实挑战,能充分暴露算法的弱点。三是真值精度高,由Vicon运动捕捉系统提供,精度在毫米到厘米级,拿来做量化误差分析非常可靠。相比之下,TUM RGB-D数据集某些序列没有IMU真值,KITTI偏向车载场景,Euroc则是室内小型无人机场景里最标准、最容易复现的评测集。
1.3 这套组合能解决什么问题
把ORB-SLAM3和Euroc放到一起,本质上是做一次完整的算法验证闭环。对新手来说,跑通这个流程意味着你理解了SLAM系统的运行流程:图像输入、特征提取与匹配、初始化、局部建图、回环检测、图优化,以及视觉和IMU数据怎么融合。对做研究的人来说,Euroc给了你一个公平的擂台,你可以对比不同模式、不同序列下的ATE(绝对轨迹误差)和RPE(相对位姿误差),用数据说话。
我在实际测试中最大的体会是,Euroc虽然只有11个短序列,但每个序列的难度层次分明,从MH01到MH05、V1、V2系列,覆盖了从平坦缓慢到剧烈快速的各种运动梯度。跑完这套流程,你对ORB-SLAM3的参数感知、传感器标定理解,都会比单纯看论文深刻得多。
2. 环境准备与源码编译实录
2.1 依赖库版本选择与安装细节
在动手编译ORB-SLAM3之前,先把环境摸清楚。我推荐Ubuntu 18.04或20.04,这两个系统下的依赖兼容性问题最少。核心依赖有这几个:Pangolin(UI和可视化)、OpenCV(图像处理)、Eigen3(线性代数)、DBoW2和g2o(ORB-SLAM3自带在Thirdparty目录下)、Sophus(也是自带的)。如果要用Python绑定的评估工具,后面还会用到evo。
这里有个关键点,ORB-SLAM3官方默认的OpenCV视觉特征模块依赖需要opencv-contrib的支持。如果你装的是OpenCV 4.x,纯基础的libopencv-dev包会缺xfeatures2d模块,编译时会直接报"opencv2/xfeatures2d.hpp: No such file or directory"。最省事的方案是装OpenCV 3.4.x,或者用官方提供的opencv-contrib一起编译。我自己在Ubuntu 20.04上用OpenCV 4.2也能通过,但需要在CMakeLists里手动指定OpenCV_INCLUDE_DIRS,对新手不太友好。建议按稳妥路线来。
依赖安装命令整理如下:
# 基础编译工具 sudo apt-get install -y build-essential cmake git pkg-config # Pangolin依赖 sudo apt-get install -y libglew-dev libpython3-dev libxi-dev libxinerama-dev \ libx11-dev libwayland-dev libxkbcommon-dev wayland-protocols \ libegl-dev libglvnd-dev # Eigen3 sudo apt-get install -y libeigen3-dev # OpenCV 3.4.x(二选一,推荐用apt安装省事) sudo apt-get install -y libopencv-dev # 如果上面的opencv版本不带contrib,建议源码编译OpenCV 3.4.16我把Pangolin单独拎出来说,因为它的版本坑最折磨人。老版本的Pangolin(0.5/0.6)和新版本在视窗初始化接口上有明显变化,直接git clone最新版反而容易和ORB-SLAM3里的旧接口冲突。实操中我建议用如下版本组合:Pangolin 0.6、OpenCV 3.4.16、Eigen 3.3.7。这套组合几乎可以零报错编译通过。
2.2 编译流程与命令
依赖装好之后,进入ORB-SLAM3源码目录,直接编译就好:
git clone https://github.com/UZ-SLAMLab/ORB_SLAM3.git cd ORB_SLAM3 chmod +x build.sh ./build.shbuild.sh内部会依次编译Thirdparty里的DBoW2、g2o、Sophus,然后编译ORB-SLAM3主体。整个过程在配置好依赖的情况下,5到10分钟就能完成。如果你的机器有多核,可以把build.sh里的make -j参数调高一点,比如改成make -j8,能快不少。
编译完成后,在Examples目录下会生成几个可执行文件,比如mono_euroc、stereo_euroc、stereo_inertial_euroc、mono_inertial_euroc等。这几个就是我们一会儿要用的核心程序。
2.3 编译阶段最容易踩的几个坑
第一个坑是CUDA报错。ORB-SLAM3早期版本的部分分支在编译时会尝试启用CUDA模块,如果机器上装了CUDA但版本不匹配,或者没装CUDA但某些头文件路径残留,会直接编译失败。遇到这种问题,打开CMakeLists.txt,把跟CUDA相关的判断注释掉,或者明确设置为OFF即可。
第二个坑是Eigen版本过高。Ubuntu 22.04仓库里的Eigen是3.4+,某些接口变了,g2o编译时容易报错。解决方法就是手动安装Eigen 3.3.7,这个版本最稳。
第三个坑是内存不够。ORB-SLAM3编译时g2o部分非常吃内存,如果编译过程中卡死或者报"internal compiler error",可以检查一下机器的swap分区和可用内存,至少留出4GB以上。
提示:编译前最好把build文件夹里的旧编译缓存删干净,尤其是反复切换OpenCV版本之后。我遇到过几次改了OpenCV路径后还是报旧版本错误,删掉build目录重新编译就好了。
3. Euroc数据集下载、解压与文件结构详解
3.1 序列选择与下载策略
Euroc数据集官方托管在ETH的服务器上,包含MH01到MH05五个机器大厅序列,以及V1、V2两个厂房序列各三个难度版本,一共11个有效序列。每个序列一个压缩包,大小从几百MB到1GB不等。下载时优先选择MH01到MH05,这五个序列运动轨迹更平滑,跑出来的轨迹图也更直观。
下载地址是官方页面 http://robotics.ethz.ch/~asl-datasets/ijrr_euroc_mav_dataset/ ,如果官网下载速度不理想,可以找国内高校或社区分享的镜像链接。值得注意的是,数据集分为两个版本:带bag的ROS包版本和纯数据的ASL数据集格式版本。我们这里只需要不带bag的machine hall序列文件夹,文件名一般是MH_01_easy.zip这样的格式。
每个序列解压后会有一个mav0文件夹,这个文件夹就是ORB-SLAM3直接读取的目录。建议把11个序列全部下下来,因为后面做对比实验时,MH和V系列运动特性差异很大,能横评出算法在不同场景下的鲁棒性。
3.2 mav0目录结构逐层拆解
解压完成后,进入mav0目录,你会看到下面几个子目录和CSV文件:
mav0/ ├── cam0/ │ ├── data/ │ │ └── 1403636579763555584.png │ └── sensor.yaml ├── cam1/ │ ├── data/ │ │ └── 1403636579763555584.png │ └── sensor.yaml ├── imu0/ │ ├── data.csv │ └── sensor.yaml ├── state_groundtruth_estimate0/ │ ├── data.csv │ └── sensor.yaml ├── leica0/ │ └── ... └── ...cam0和cam1分别是左右目的图像数据,sensor.yaml里记录了相机内参、畸变模型、图像分辨率等标定参数。imu0/data.csv是IMU采样数据,每行包含时间戳、角速度和加速度。state_groundtruth_estimate0/data.csv是运动捕捉系统给出的真值轨迹,用于精度评估。
这里要特别提醒,ORB-SLAM3自带的EuRoC.yaml配置文件里,有些参数需要和你下载的具体序列的sensor.yaml匹配。比如相机内参fx、fy、cx、cy,以及IMU的噪声密度、随机游走参数。官方给的示例配置虽然是综合了几个序列的平均值,但不同序列之间差异不大,直接默认用问题也不大。如果你追求更高精度,可以把配置文件改成对应序列sensor.yaml里的精确值。
3.3 时间戳文件和话题名的对应关系
ORB-SLAM3的Examples目录下有个EuRoC_TimeStamps文件夹,里面存放了每个序列的图像时间戳文件,比如MH01.txt、V101.txt等。运行程序时,你需要把这个txt文件的路径作为参数传给可执行文件。它的作用就是告诉ORB-SLAM3“哪张图片对应哪个时间点”,方便系统按时间序列处理数据。
很多第一次跑的人容易在这里蒙圈,分不清时间戳到底对应的是cam0还是cam1。其实ORB-SLAM3对于EuRoC数据集的单目和双目模式,都是使用cam0的图像流和对应时间戳。只有在双目惯性模式里,时间戳参数才会同时涉及cam0、cam1和imu0三个文件。后面讲到运行命令时,我会把它们的对应关系单独说明。
4. 正式跑通:单目、双目、双目惯性模式命令详解
4.1 单目模式下的运行命令与注意事项
单目模式是ORB-SLAM3里最简化、也最能看明白算法流程的模式。先确保数据集路径和时间戳路径都放在一个方便引用的位置,然后执行:
./Examples/Monocular/mono_euroc \ ./Vocabulary/ORBvoc.txt \ ./Examples/Monocular/EuRoC.yaml \ /path/to/MH01/mav0/cam0/data \ ./Examples/Monocular/EuRoC_TimeStamps/MH01.txt这里第一个参数是词袋模型文件,第二个是相机和ORB特征参数配置,第三个是cam0图像目录,第四个是时间戳文件。
跑起来之后,你会看到Pangolin窗口弹出,左侧是当前帧的ORB特征点可视化,右侧是相机轨迹和地图点的实时构建。这个过程非常直观,你能看到特征点像星星一样在图像上闪烁,地图点逐渐铺满画面。单目模式存在尺度的不可观测性,所以轨迹的绝对尺度是不知道的,轨迹看起来会比实际偏小或偏大,这在后面评估时需要注意。
单目模式最容易出问题的地方是初始化阶段。如果序列开头有大范围的旋转或者低纹理区域,初始化可能失败,表现为Pangolin窗口里迟迟没有地图点出现。遇到这种情况,直接换MH01这类从平滑运动开始的序列即可,或者增加EuRoC.yaml中的特征点数量,比如把ORBextractor.nFeatures从默认值调高。
4.2 双目与双目惯性模式:传感器融合的魅力
双目模式下,ORB-SLAM3可以恢复绝对尺度,轨迹精度会有明显提升。执行命令:
./Examples/Stereo/stereo_euroc \ ./Vocabulary/ORBvoc.txt \ ./Examples/Stereo/EuRoC.yaml \ /path/to/MH01/mav0/cam0/data \ /path/to/MH01/mav0/cam1/data \ ./Examples/Stereo/EuRoC_TimeStamps/MH01.txt注意,双目模式时左右目的时间戳是相同的,ORB-SLAM3内部会按左右目时间戳配对图像帧。如果数据集中左右目图像不是严格同步的,ORB-SLAM3会做时间戳最近邻匹配,所以轻微的时间偏差问题不大。
双目惯性模式是ORB-SLAM3的“完全体”,同时输入双目图像和IMU数据。执行命令会稍微复杂一些:
./Examples/Stereo-Inertial/stereo_inertial_euroc \ ./Vocabulary/ORBvoc.txt \ ./Examples/Stereo-Inertial/EuRoC.yaml \ /path/to/MH01/mav0 \ ./Examples/Stereo-Inertial/EuRoC_TimeStamps/MH01.txt \ ./Examples/Stereo-Inertial/EuRoC_TimeStamps/MH01.txt \ ./Examples/Stereo-Inertial/EuRoC_TimeStamps/MH01.txt这里第一个时间戳对应cam0图像,第二个对应imu0 IMU数据,第三个对应地面真值(用于对齐)。实际使用中,这三个文件的内容略有差异,因为图像、IMU、真值的采样频率和时间段不完全一致。ORB-SLAM3源码里默认读取同一序列的这几个文件,文件名通常一样但内容不同。
双目惯性模式下,系统会先利用IMU数据进行视觉惯性初始化,这个过程通常在数秒内完成。IMU的加速度计和陀螺仪偏置会被在线估计并持续优化,所以整个轨迹在快速旋转和剧烈加速阶段依然能保持稳定的姿态估计。我第一次跑到V2_03复杂序列时,视觉跟踪差点丢失,但IMU数据“续命”成功了,这种融合的稳定感是纯视觉方案给不了的。
4.3 结果输出与文件解读
ORB-SLAM3正常跑完一个序列后,会在终端打印"System: Saving trajectory to..."类似的提示,然后自动把轨迹保存到两个文件:
- KeyFrameTrajectory.txt:只包含关键帧的轨迹
- CameraTrajectory.txt:包含每一帧相机位姿的轨迹
这两个文件每行格式都是:时间戳 tx ty tz qx qy qz qw,时间戳单位为秒,位置单位通常为米,四元数表示姿态。
需要注意的是,只有在程序正常退出(比如按Ctrl+C或者在Pangolin窗口按ESC关闭)时,保存动作才会触发。如果你用kill -9强制杀掉进程,轨迹文件可能没来得及写入,最后得到的是空文件或半个文件。所以跑完一个序列,最好等Pangolin窗口关闭后,再确认一下文件大小是否正常。
5. 轨迹精度评估:用evo对比真值与ORB-SLAM3输出
5.1 evo安装和基本用法
光有轨迹还不算完,评测SLAM算法最关键的环节是量化误差。这里推荐用evo这个Python工具,它专门处理SLAM轨迹评估,支持TUM、KITTI、EuRoC等多种格式。安装非常简单:
pip install evo --upgrade --no-binary evo如果系统里没有pip,先装一下python3-pip和python3-tk,因为evo绘图需要tkinter。
evo的核心命令有两个:evo_ape用于算绝对位姿误差,evo_rpe用于算相对位姿误差。ATE反映的是整条轨迹的全局一致性,RP E反映的是局部运动误差。对SLAM系统来说,这两个指标缺一不可。
5.2 对齐方式与评估命令
评估Euroc数据时,真值文件路径是mav0/state_groundtruth_estimate0/data.csv,估计文件是ORB-SLAM3输出的KeyFrameTrajectory.txt。但直接拿这两个文件比较是不公平的,因为估计值的坐标原点、朝向、甚至尺度(单目情况下)都和真值坐标系不一致。所以必须先做坐标对齐。
对于双目和双目惯性模式,尺度接近1,只需要做Sim(3)或SE(3)对齐。evo命令中加上-a参数会自动计算最优的Sim(3)变换把估计轨迹对齐到真值轨迹。典型的ATE评估命令如下:
evo_ape euroc \ /path/to/MH01/mav0/state_groundtruth_estimate0/data.csv \ ./KeyFrameTrajectory.txt \ -va --plot --plot_mode xz-v表示显示详细信息,-a表示自动对齐,--plot会生成一个可视化的误差轨迹图,--plot_mode xz则把轨迹投影到x-z平面展示(机器人通常在这个平面运动,看起来最直观)。
如果跑的是单目模式,由于尺度未知,必须使用Sim(3)对齐,同时评估结果中会多出一个尺度因子(scale)指标。evo足够聪明,会自动处理,但你要知道这个尺度因子存在,它是单目SLAM固有的尺度模糊性的体现。
5.3 评估结果怎么读
评估完成后,终端会打印RMSE、mean、median、std等统计指标。对这些数值的理解,我给出几个实用参考:
- RMSE(均方根误差)是最常用的综合误差指标,单位是米。Euroc序列上,双目惯性模式MH序列的ATE RMSE通常在0.05到0.15米之间,纯双目会稍差一点,单目如果做了良好初始化也能到0.2米以下。
- 如果你的结果远超这些参考值,先别急,检查一下时间戳文件、IMU参数、以及是否做了坐标对齐,出问题的概率远大于算法本身。
- 另外,评估结果里会给一个“max”误差,这个代表轨迹中最差的一个点。如果max特别大,说明中间某段跟踪丢失或漂移严重,可以配合绘图查看是哪段出的问题。
evoi生成的图里,轨迹线越粗或颜色越红的地方,误差越大。这能帮你定位到具体是哪个时间段或哪个空间位置出现了大的漂移,对调试算法参数相当有帮助。
6. 高频报错与避坑清单
6.1 编译阶段典型故障
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
| opencv2/xfeatures2d.hpp: No such file or directory | OpenCV缺少contrib模块 | 安装opencv-contrib或改用OpenCV 3.4.x |
| g2o: symbol lookup error | Eigen版本冲突 | 降级Eigen到3.3.x |
| cuda_runtime.h: No such file | 编译了CUDA模块但CUDA环境异常 | 在CMakeLists中禁用CUDA |
| GLIBCXX_3.4.29 not found | gcc/g++版本过旧 | 升级gcc到9以上 |
| Pangolin: undefined reference | Pangolin版本不匹配 | 切换到0.6版本 |
6.2 运行阶段高频问题
| 症状 | 可能原因 | 排查顺序 |
|---|---|---|
| 程序启动后秒退 | 数据集路径或时间戳路径不存在 | 检查参数路径,确认mav0目录结构 |
| 初始化失败 | 序列开头缺少纹理或运动过猛 | 换用MH01序列,或增大ORB特征数量 |
| 轨迹坡度/尺度异常 | 相机内参和IMU参数与实际序列不匹配 | 对照sensor.yaml修正EuRoC.yaml |
| Ctrl+C后无轨迹文件 | 进程被强制杀死,未触发保存回调 | 等待正常退出,或手动在代码中加入保存逻辑 |
| 跑得很慢,实时性差 | CPU占用过高,Pangolin渲染开销大 | 关闭系统特效,或用headless模式运行 |
6.3 我的几个独家排查技巧
最后一个建议,如果你不是专门研究特征点法SLAM理论,第一次跑ORB-SLAM3时不要试图改算法参数。先用默认配置把三个模式全部跑通,再逐步观察差异。默认配置是作者在多个序列上调出来的甜点参数,对新数据集未必最优,但对Euroc来说已经足够稳定。
另外,我强烈建议在跑每一个序列之前,先用evo把真值轨迹画出来看一眼。MH序列和V序列的运动范围、运动速度差别非常大,提前了解真值轨迹的形状,后面再对比ORB-SLAM3输出的轨迹,一眼就能看出哪段漂移离谱。
踩过几次坑之后,我最深刻的体会是:ORB-SLAM3跑Euroc这套组合,真正难的并不是运行本身,而是环境配置和数据准备阶段的这种“小折磨”。但只要把这套流程完整走通一遍,你对SLAM系统如何读取传感器数据、如何组织特征和关键帧、如何输出并评估轨迹,都会建立起一个非常扎实的整体框架。所以遇到报错千万别烦躁,每一步调试都是在帮你理解系统内部的工作原理。