资讯动态

ORB-SLAM2跑自己的图片序列:从编译到轨迹评估的完整指南

发布时间:2026/10/25 18:15:48 来源:尧图企业网站定制
简介这份资源面向视觉SLAM初学者与需要跑通自定义数据集的开发者聚焦ORB SLAM2在自采图片序列上的实际应用帮助解决从视频抽帧到生成rgb.txt、再到加载运行自有数据的完整链路问题。压缩包为gz格式共4个文件约4.38MB包含2个Python脚本、1个mp4视频和1个txt文本脚本可用于视频逐帧提取与rgb.txt时间戳生成视频提供原始素材文本则记录图片路径与时间戳便于直接复现实验。已有5382人学习下载说明其在SLAM入门实践中具有一定参考价值。资源围绕特征检测与匹配、关键帧选择、跟踪定位、闭环检测、重定位、稀疏建图与全局优化等环节给出可对照的数据组织方式读者可据此理解ORB SLAM2读取图片序列的输入规范并借助示例素材完成自定义场景的定位与建图练习积累配置参数调整与运行排错的实践经验。1. 用 ORB-SLAM2 跑自己的图片序列从一份能直接编译的源码包说起手头有一批自己拍的图片序列想验证一下视觉 SLAM 的位姿估计效果结果卡在第一步——官方仓库只给了示例数据集自己的图片怎么喂进去、相机内参怎么填、时间戳文件怎么生成文档里一句没提。这份 ORB-SLAM2 源码包解决的正是这个断点它把编译依赖、示例配置、图片序列入口都整理好了拿到手改几个路径就能跑通单目、双目、RGB-D 三种模式。适合两类人一是刚接触视觉 SLAM、想用真实图片验证课程里那些概念的新手二是手里有自己采集的序列、需要快速搭一套基线做对比的从业者。下面按「资源是什么 → 怎么配 → 怎么跑 → 坑在哪」的顺序拆参数和命令都能直接抄。2. 先看清这份源码包的骨架目录、依赖与三种模式入口拿到一个 SLAM 源码包最忌讳上来就cmake ..。先花十分钟把目录结构和依赖关系摸清楚后面编译报错能少一半。ORB-SLAM2 的工程组织其实很规整核心就三块src/放算法实现include/放头文件Examples/放各传感器模式的入口程序和配置。真正决定你能不能跑通自己数据的是Examples/下面那几个xxx.cc和配套的*.yaml。2.1 目录结构与关键文件定位一份典型的 ORB-SLAM2 源码包展开后大致是这样ORB_SLAM2/ ├── src/ # 核心算法Tracking、LocalMapping、LoopClosing ├── include/ # 对应头文件 ├── Examples/ │ ├── Monocular/ # 单目入口 mono_xxx.cc 相机配置 │ ├── Stereo/ # 双目入口 │ ├── RGB-D/ # RGB-D 入口 │ └── ROS/ # ROS 节点封装可选 ├── Thirdparty/ # DBoW2、g2o、Pangolin 等依赖 ├── Vocabulary/ # ORB 词典 ORBvoc.txt └── CMakeLists.txt你要改的只有两处Examples/模式/下的入口程序里读图片的路径以及同目录下*.yaml里的相机内参。Vocabulary/ORBvoc.txt是回环检测用的词典文件不小第一次加载会慢几秒这是正常的不是卡死。Thirdparty/里通常已经带了 DBoW2 和 g2o 的源码Pangolin 需要系统里自己装这是编译阶段最常见的依赖缺口。2.2 编译依赖与版本边界ORB-SLAM2 对依赖版本比较敏感尤其是 OpenCV 和 Eigen。常见做法是 OpenCV 用 3.x 或 4.x 的早期版本Eigen 用 3.2 以上Pangolin 用较新的稳定版。C 标准要开到 C11老编译器比如默认 C98 的会在CMakeLists.txt里直接报错。编译流程分两步先编 Thirdparty 再编主工程# 进入源码根目录 cd ORB_SLAM2 # 先给脚本执行权限再编译第三方库 chmod x build.sh ./build.shbuild.sh里实际做的是依次进入Thirdparty/DBoW2、Thirdparty/g2o执行 cmake 和 make最后编译主工程并生成lib/libORB_SLAM2.so。如果这一步在某个 Thirdparty 子目录里失败先单独进去手动cmake .. make看具体报错比在脚本里被吞掉强。常见失败点是 g2o 找不到 Eigen或者 Pangolin 头文件路径没被找到——前者检查 Eigen 是否装全/usr/include/eigen3是否存在后者确认 Pangolin 装完后find_package(Pangolin)能找到。提示编译前先确认cmake --version不低于 2.8gcc --version支持 C11。版本不满足时不要硬改 CMakeLists 里的标准号先升级工具链否则后面运行期会出现莫名其妙的段错误。2.3 三种模式怎么选先想清楚你的数据长什么样单目、双目、RGB-D 的入口程序不同配置文件的字段也不同选错模式会直接跑不起来。判断依据很简单你采集的是单摄像头视频帧就走单目是左右两个同步摄像头走双目是有深度图配彩色图走 RGB-D。模式入口程序配置关键字段适用数据单目mono_xxx.ccCamera.fx/fy/cx/cy单摄像头图片序列双目stereo_xxx.cc上述 Camera.bf、ThDepth左右目同步序列RGB-Drgbd_xxx.cc上述 DepthMapFactor彩色图 深度图单目模式有个绕不开的特性尺度不可观。你跑出来的轨迹形状对但绝对尺度是任意的这是单目 SLAM 的固有性质不是代码 bug。如果你的应用需要真实尺度要么上双目/RGB-D要么在单目轨迹上额外做尺度对齐。这一点在选模式时就要想清楚别跑完才发现尺度对不上。3. 把自己的图片序列喂进去时间戳、内参与配置文件三件套这一章是整篇的核心。官方示例用的是打包好的数据集路径和格式都固定换成自己的图片要补的是三样东西图片命名与时间戳、相机内参 yaml、入口程序里的路径。三样缺一不可顺序也别乱——先定格式再填内参最后改入口。3.1 图片命名与时间戳文件生成ORB-SLAM2 读图片序列时入口程序里通常是一个循环按索引拼文件名同时从一个时间戳文件里逐行读时间。所以你的图片要么按固定宽度数字命名如000001.png、000002.png要么改入口程序里的拼接逻辑。最省事的做法是统一重命名成六位补零的格式。时间戳文件的格式是每行一个时间戳秒浮点行数与图片数一一对应。如果你采集时没记录时间常见做法是按固定帧率反推比如 30fps 就每帧间隔 1/30 秒。下面这段脚本把任意命名的图片批量重命名并生成时间戳文件import os img_dir my_sequence # 你的图片目录 fps 30.0 # 采集帧率没有记录就按这个反推 ext .png # 图片扩展名按实际改 files sorted([f for f in os.listdir(img_dir) if f.endswith(ext)]) with open(os.path.join(img_dir, times.txt), w) as fout: for i, fname in enumerate(files): # 六位补零重命名保持顺序 new_name f{i:06d}{ext} os.rename(os.path.join(img_dir, fname), os.path.join(img_dir, new_name)) # 时间戳从 0 开始按帧率累加 fout.write(f{i / fps:.6f}\n) print(f处理 {len(files)} 帧时间戳写入 times.txt)这段脚本做了两件事重命名保证字典序与采集顺序一致生成times.txt供入口程序读取。参数上fps只影响时间戳的绝对间隔不影响位姿估计的相对结果但如果你后面要做轨迹对齐或速度估计这个值要尽量准。ext一定要和实际图片格式一致混用.jpg和.png会导致读图失败。重命名前建议先备份原图os.rename是不可逆的。3.2 相机内参 yaml 怎么填内参是单目 SLAM 精度的命门。fx、fy、cx、cy四个值来自相机标定没有标定数据的话跑出来的轨迹会明显漂移甚至跟踪丢失。yaml 文件的结构大致如下以单目为例%YAML:1.0 # 相机内参单位像素 Camera.fx: 517.3 Camera.fy: 516.5 Camera.cx: 318.6 Camera.cy: 255.3 # 畸变系数k1 k2 p1 p2 k3 Camera.k1: 0.2624 Camera.k2: -0.9531 Camera.p1: -0.0054 Camera.p2: 0.0026 Camera.k3: 0.0 # 图像尺寸 Camera.width: 640 Camera.height: 480 # 帧率 Camera.fps: 30.0 # RGB 转灰度彩色图设为 1 Camera.RGB: 1fx、fy是焦距的像素表示cx、cy是主点坐标通常接近图像中心但不完全等于中心。畸变系数如果相机已经做过去畸变可以全填 0没做过就按标定结果填ORB-SLAM2 内部会做去畸变处理。Camera.RGB: 1表示输入是彩色图、内部转灰度如果你的图本来就是灰度填 0。Camera.fps要和实际帧率一致它影响跟踪时的运动模型假设。注意内参填错最典型的表现是「能初始化但很快跟丢」或「轨迹整体缩放不对」。如果跑自己的数据一直丢先别怀疑算法拿标定板重新标一次内参比调任何参数都管用。3.3 改入口程序路径、词典与配置加载入口程序里要改的通常是三处图片目录、时间戳文件路径、yaml 配置路径。以单目入口为例核心逻辑是构造System对象、逐帧读图、调用TrackMonocular// 加载词典和配置路径按你的实际目录改 ORB_SLAM2::System SLAM( /path/to/Vocabulary/ORBvoc.txt, // 词典路径 /path/to/my_mono.yaml, // 相机配置 ORB_SLAM2::System::MONOCULAR, // 模式 true); // 是否开可视化 // 读时间戳 std::ifstream fTimes(/path/to/my_sequence/times.txt); std::string line; int ni 0; while (std::getline(fTimes, line)) { double t std::stod(line); // 按六位补零拼图片名 char buf[100]; snprintf(buf, sizeof(buf), /path/to/my_sequence/%06d.png, ni); cv::Mat im cv::imread(buf, cv::IMREAD_UNCHANGED); if (im.empty()) break; // 读不到就停避免空帧崩溃 SLAM.TrackMonocular(im, t); // 时间戳单位秒 ni; } SLAM.Shutdown();几个参数要留意TrackMonocular的第二个参数是时间戳单位是秒和times.txt里的一致IMREAD_UNCHANGED保留原始通道彩色图后面由Camera.RGB控制转换im.empty()的判断不能省图片数比时间戳多或少都会在这里暴露。词典路径和 yaml 路径用绝对路径最稳相对路径在不同工作目录下跑容易找不到文件。改完重新make一次即可不用重编 Thirdparty。4. 跑通之后看什么轨迹保存、可视化与结果判读程序不报错、窗口里能看到特征点和轨迹只说明跑起来了不代表结果可信。这一章讲怎么把轨迹存下来、怎么判断这次跑得对不对以及结果异常时从哪几个方向排查。4.1 轨迹文件保存与格式ORB-SLAM2 在Shutdown()时会自动把轨迹写到当前工作目录单目模式通常是CameraTrajectory.txt和KeyFrameTrajectory.txt。前者是每帧位姿后者是关键帧位姿。格式是每行「时间戳 tx ty tz qx qy qz qw」四元数顺序是 x y z w别和别的工具搞混。如果没生成文件检查入口程序里System构造时最后一个参数是否保存以及Shutdown是否被调用。有些改过的入口程序把保存逻辑注释掉了跑完窗口一关什么都没留下这是血泪经验——第一次跑一定先确认轨迹文件落地了再谈精度。4.2 用 evo 做轨迹对齐与误差评估轨迹存下来后最直接的验证是和自己采集时的参考轨迹如果有做对比或者至少看轨迹形状是否合理。evo是常用的轨迹评估工具支持 TUM 格式。把CameraTrajectory.txt转成 TUM 格式时间戳 位置 四元数空格分隔后可以直接喂进去# 安装 evo pip install evo --upgrade # 画轨迹看形状是否闭合、是否有跳变 evo_traj tum CameraTrajectory.txt --plot # 有参考轨迹时做绝对位姿误差评估 evo_ape tum groundtruth.txt CameraTrajectory.txt --align --plot--align会先做尺度或刚体对齐再算误差单目轨迹必须加这个参数否则尺度差异会让误差大得没法看。evo_traj画出来的图重点看两处轨迹有没有突然的折返或飞点跟踪丢失后重定位的典型表现以及整体形状是否和你实际走的路线一致。形状对但尺度不对是单目正常现象形状都不对回去查内参和图片顺序。4.3 结果异常的四个排查方向跑出来结果不对按这个顺序查能覆盖大部分情况第一图片顺序。重命名后确认字典序和采集顺序一致000010排在000009后面没问题但如果原始命名是img1、img10、img2这种排序会乱必须补零。第二时间戳单调性。times.txt必须严格递增重复或倒序会让跟踪的运动模型失效。生成脚本里按索引累加天然单调手动改过的要复查。第三内参和实际分辨率。yaml 里的Camera.width/height必须和图片实际尺寸一致图片被缩放过的尤其容易漏改表现是特征点提取正常但位姿明显偏。第四纹理条件。白墙、纯色地面、强逆光这些场景 ORB 特征本来就少跟踪丢失是数据问题不是代码问题。遇到这种序列要么换场景要么接受它跑不完全程。5. 避坑与常见问题编译、运行、精度三类翻车现场这一章按「现象 → 原因 → 解决」列几条实际踩过的坑都是跑自己数据时高频出现的照着对号入座能省不少时间。现象build.sh在 g2o 处报找不到 Eigen。原因Eigen 装了但头文件路径没被 CMake 找到或者装的是不完整版本。 解决确认/usr/include/eigen3/Eigen存在在 g2o 的 CMakeLists 里显式加include_directories(/usr/include/eigen3)再单独编译 g2o。现象程序启动即崩报 Pangolin 相关符号未定义。原因Pangolin 版本与源码不匹配或编译时链接顺序有问题。 解决重装 Pangolin 稳定版装完sudo ldconfig刷新库缓存再重编主工程。实在搞不定可以先关掉可视化System构造最后一个参数设 false验证算法本身是否正常。现象能初始化跑几十帧后跟踪丢失反复重定位。原因内参不准、时间戳间隔与实际运动不匹配或图片序列本身有大量模糊帧。 解决先重标内参再检查times.txt间隔是否和实际采集帧率一致最后抽几帧看清晰度运动过快导致的模糊帧 ORB 提不出稳定特征属于数据质量问题。现象轨迹形状对但和参考轨迹比尺度差一个常数。原因单目 SLAM 尺度不可观这是固有性质。 解决不要试图调参「修」尺度用evo_ape --align做对齐后评估或改用双目/RGB-D 数据。需要真实尺度时在轨迹后处理阶段用已知距离做尺度恢复。现象RGB-D 模式跑出来深度全错轨迹乱飞。原因DepthMapFactor没按深度图的实际量化单位填。深度图若是 16 位、单位毫米这个因子通常是 1000单位米则是 1。 解决查深度图的编码方式改 yaml 里的DepthMapFactor用单帧深度值对照真实距离验证一次再跑全程。6. 进阶用关键帧轨迹做快速回归把每次改动都验一遍跑通一次不算完真正省时间的是把「改配置 → 重跑 → 看结果」变成一个可重复的回归流程。我一般会固定一段短序列一两百帧、纹理充足、运动平缓把它当作基线每次动内参、动入口程序、换编译选项之后都拿它跑一遍用关键帧轨迹的终点位置和轨迹长度做快速比对。关键帧轨迹比每帧轨迹短噪声小适合做这种粗粒度回归。具体做法是写个小脚本跑完后自动提取KeyFrameTrajectory.txt的帧数和终点坐标和上一次的记录比import numpy as np def summarize(path): data np.loadtxt(path) # 每行: t tx ty tz qx qy qz qw pos data[:, 1:4] # 取平移部分 length np.sum(np.linalg.norm(np.diff(pos, axis0), axis1)) return len(data), pos[-1], length n, end, length summarize(KeyFrameTrajectory.txt) print(f关键帧数 {n}, 终点 {end}, 轨迹长度 {length:.3f})np.diff算相邻关键帧的位移再累加得到轨迹总长度终点坐标反映整体漂移方向。这两个指标不用很精确只要同一段序列两次运行的差异在可接受范围内就说明改动没有引入明显退化。如果关键帧数突然大幅减少多半是跟踪变差、丢帧增多回去查最近改的那处配置。这个习惯的价值在于把「感觉跑得还行」变成「有数字可比」。SLAM 的玄学之处就在于很多改动单看一次结果看不出好坏跑三次两次不一样没有基线就只能凭印象。固定序列加固定指标至少能挡住那些明显让结果变差的改动。从那以后我每次动 ORB-SLAM2 的配置或入口代码都强制先跑一遍这段基线序列再往下做省下来的返工时间远比写脚本的几分钟多。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑