用自己的图片序列跑通ORB SLAM2:从数据准备到轨迹输出的完整指南
发布时间:2026/10/12 6:32:56 锦皓数字建站

简介面向视觉SLAM初学者与机器人开发者解决如何利用ORB SLAM2处理自采图片序列完成定位与建图的问题。资源以ORB SLAM2为切入点覆盖从视频逐帧提取图像、生成带时间戳的rgb.txt、编写辅助脚本到修改配置文件并运行数据集的完整流程特别适合不熟悉TUM/EuRoC标准数据集格式、希望跑通自建数据的读者。压缩包共4个文件包含Python脚本、示例视频和rgb.txt参考文件整体仅4.38MB轻量易下载两个py脚本分别承担图像提取与数据集文件组织等工作mp4提供原始录制素材txt展示ORB SLAM2读取序列所需的格式样例。已有5377人学习下载。借助该资源可避开自制SLAM数据集的常见坑点快速掌握图片序列命名、时间戳生成、参数调整等关键环节进而将ORB SLAM2无缝迁移到自己的采集数据上。1. 先别急着跑官方样例用自己的图片序列数据集踩的才是真坑把 ORB SLAM2 跑通官方的样例序列只能算环境没问题真正检验这套方案能不能为你所用是把手头一段普普通通的图片序列数据集塞进去看它能不能完成初始化、持续追踪并输出一条不飘的轨迹。很多找我聊这个问题的人卡点都不在编译而在数据准备、相机参数和配置文件这三处。这篇笔记把从原始照片到跑通 ORB SLAM2 的完整链路拆开采集规范、时间戳生成、内参标定、yaml 改写、编译运行、常见翻车点和结果验证。适合手里已经有一批连续图片、想验证定位建图效果或者正准备搭视觉 SLAM 实验环境的开发者和研究者。2. 先造出一份能被 ORB SLAM2 识别的图片序列数据集采集、命名与时间戳自己的图片序列要能被这套系统消费核心不是图片本身而是“目录结构 rgb.txt 时间戳文件 相机参数”这一整套格式。ORB SLAM2 的 mono_tum 入口只认一种组织方式数据集目录下有一张图片清单文件每一行是“时间戳 图片相对路径”。这条规则定死了后面的采集、命名、抽帧全都要围绕它设计不然运行时会报出一堆看不懂的加载错误。2.1 拍摄阶段就要避免的三类问题模糊、纯旋转和自动对焦采集质量直接决定 ORB SLAM2 能不能跑起来。单目前端靠 ORB 特征点做匹配画面一旦运动模糊角点检测数量会断崖式下跌Tracking 线程就会反复尝试重定位。我自己拍素材的习惯是相机固定对焦手动对焦画面主体不要是纯色墙面或大面积天空移动时以平移为主避免原地旋转。单目初始化需要两帧之间有足够视差纯旋转时本质矩阵退化系统会一直停在 “try to initialize” 状态。光照条件也要稳定避免突然过曝或突然变暗。ORB 的 FAST 角点对亮度变化有一定鲁棒性但亮暗跳变会带来大量不稳定特征点轻则局部地图抖动重则触发关键帧插入风暴。如果场景纹理稀疏比如走廊白墙、桌面拍摄时可以在画面里保留一些有棱角的物体或者走后调整 ORB 参数来补救——参数怎么调第 3 章会专门讲。2.2 生成标准的时间戳文件 rgb.txt最少脚本与路径规则假设你已经有了一堆 JPG最常见的做法是用一个 Python 脚本扫描目录按固定间隔生成时间戳。这里的时间戳单位是秒格式要求 6 位小数后面跟空格和相对路径。给一个我常用的生成脚本import os import glob img_dir /home/user/my_sequence # 改成你的图片目录 img_files sorted(glob.glob(os.path.join(img_dir, *.jpg))) with open(os.path.join(img_dir, rgb.txt), w) as f: for idx, img_path in enumerate(img_files): # 用序号模拟时间戳每帧间隔 0.05 秒对应 20fps ts idx * 0.05 rel_path os.path.basename(img_path) f.write(f{ts:.6f} {rel_path}\n) print(f{ts:.6f} {rel_path})这段脚本的逻辑是把目录下的 JPG 按文件名排序然后用序号乘以固定帧间隔生成时间戳。需要特别注意两点。第一文件名排序必须是字典序如果图片名是 1.jpg、2.jpg 这种还好一旦出现 10.jpg排序就会变成 1、10、2序列顺序全错建议文件名统一用 %04d 格式补零。第二间隔 0.05 秒对应 20fps如果你的实际拍摄帧率是 30fps要改成 0.033333。时间戳精度保留 6 位小数是为了满足 ORB SLAM2 内部的数值比较逻辑少了可能会出现两帧时间戳完全相等的情况。这是我反复踩过的坑帧率填错不会报错但轨迹会整体漂移因为 Tracking 线程按真实时间差来预测运动模型喂给它的时间间隔和实际不符运动模型从第一步就是错的。所以要么用固定帧率视频抽帧要么在拍摄时锁定帧率不要用手机默认“自动帧率”去拍那样每帧间隔是抖动的。2.3 从视频抽帧和固定帧率最匹配的序列来源如果你不想一张张按快门更稳的做法是拍一段固定帧率的视频然后用 ffmpeg 抽帧ffmpeg -i input.mp4 -vf fps20 -qscale:v 2 frames/%04d.jpg这个命令把 input.mp4 以每秒 20 帧的节奏抽成一帧帧 JPG%04d 表示四位序号补零输出到 frames 目录下。参数解释fps20 是抽帧频率要和后面 rgb.txt 里的时间戳间隔严格对应如果这里写 20时间戳间隔就是 0.05 秒qscale:v 2 是 JPG 编码质量数值越小质量越高这里 2 能保证画面细节不糊特征提取的稳定性会好很多。视频抽帧相比逐张拍照有几个明显优势一是帧间隔恒定生成的时间戳和真实节奏一致二是方便控制运动速度拍摄时只要缓慢平移抽帧出来后就是一套规范序列。缺点是需要额外注意运动模糊——手持设备边走边拍很容易拖影解决办法是拍的时候让手机慢一点或者用云台稳定器。抽完帧以后再跑上面那段 Python 脚本生成 rgb.txt就能得到一套 ORB SLAM2 能直接消费的图片序列数据集了。3. 相机标定与配置文件改写跑偏还是跑飞全看这里图片序列准备好了下一步是让 ORB SLAM2 知道你的相机长什么样。它对相机内参的依赖是硬性的内参决定了特征点反投影到三维空间的角度畸变系数影响匹配时是否需要在归一化平面上纠偏。如果这一步随便填最典型的结果是初始化能过建出来的地图却弯弯曲曲回环闭合时误差大得离谱。3.1 单目相机内参标定的两种常见做法第一种做法也是最通用的是使用 OpenCV 的棋盘格标定流程。打印一张棋盘格标定板用待标定相机从不同角度拍 15~20 张照片尽量让棋盘格出现在画面边缘和四角。然后利用 findChessboardCorners 检测角点再用 calibrateCamera 求出内参矩阵和畸变系数。下面是一段可用的标定脚本骨架import cv2 import numpy as np import glob pattern_size (9, 6) # 棋盘格内角点数 objp np.zeros((pattern_size[0] * pattern_size[1], 3), np.float32) objp[:, :2] np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 1) obj_points [] img_points [] for fname in sorted(glob.glob(calib/*.jpg)): img cv2.imread(fname) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, corners cv2.findChessboardCorners(gray, pattern_size, None) if ret: obj_points.append(objp) img_points.append(corners) ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera( obj_points, img_points, gray.shape[::-1], None, None) print(内参矩阵:\n, mtx) print(畸变系数:, dist.ravel())这里的 pattern_size 是棋盘格内角点数比如一个 10x7 的棋盘格内角点数是 9x6这个数必须和你打印的标定板一一对应填错会导致检测全部失败。mtx 输出是 3x3 的内参矩阵里面就是 fx、fy、cx、cydist 输出的是畸变系数顺序是 k1、k2、p1、p2、k3和 ORB SLAM2 的 yaml 配置文件要严格对齐。第二种做法是使用带标定功能的工业相机 SDK 自带的标定工具比如某类相机厂商的配套软件可以直接导出内参。这种方案的优点是流程标准化缺点是只对自家相机有效换一个摄像头就得重新标。无论用哪种方式最终产出都是 fx、fy、cx、cy 和一组畸变系数记下来备用。3.2 yaml 配置改写眼对眼核对五个数字ORB SLAM2 的单目入口会加载一个 yaml 文件里面包含相机模型、内参、畸变、图像尺寸和帧率。下面是一个典型的配置片段需要你把自己的标定结果填进去Camera: 1 Camera.fx: 458.654 Camera.fy: 457.296 Camera.cx: 367.215 Camera.cy: 248.375 Camera.k1: -0.283408 Camera.k2: 0.073959 Camera.p1: 0.000193 Camera.p2: 1.76187e-05 Camera.width: 640 Camera.height: 480 Camera.fps: 20.0这里最容易犯的错是把 fx、fy 填反或者把 k3 也塞进去。ORB SLAM2 的默认相机模型是针孔模型畸变模型只读取 k1、k2、p1、p2 四个参数多填 k3 并不会报错但畸变校正时系数顺序整体错位边角区域会越来越歪。width 和 height 必须是图片的真实分辨率如果抽帧时做过缩放这两项要和缩放后的尺寸一致否则投影矩阵算出来的视场角是错的初始化阶段选出的初始关键帧对就会偏。fps 这一项要和 rgb.txt 里的时间戳间隔匹配。举例来说rgb.txt 里每行间隔 0.05 秒fps 就是 20.0如果这里写成 30系统判断关键帧间隔的节奏就乱了关键帧数量和地图规模都会偏离预期。我的检查顺序是先确认图片分辨率再填 fx fy cx cy再填畸变最后回头核对 fps。3.3 特征点数量与金字塔参数影响鲁棒性的三个旋钮相机参数之外yaml 里还有一组控制特征提取的参数它们对跑自己的序列影响很大。表格里这几项是必须知道的参数名默认值说明与调整方向ORBextractor.nFeatures1000每帧提取的特征点上限纹理丰富可以保持纹理稀疏降到 600~800ORBextractor.scaleFactor1.2金字塔每层缩放比1.2 适合尺度变化大的场景纯平面可改 1.1ORBextractor.nLevels8金字塔层数层数越多越能应对尺度变化计算量也越大ORBextractor.iniThFAST20初始 FAST 角点响应阈值阈值越高角点越少越稳定ORBextractor.minThFAST7低阈值层角点响应阈值纹理弱时降低到 5 能挽救特征实际调参时我一般先用一段固定长度、运动路线明确的序列当测试集改一个参数跑一遍看两个指标追踪丢没丢过以及关键帧数量是否异常。如果画面纹理弱把 iniThFAST 从 20 降到 10 左右能明显提高特征点数量但如果降到太低会出现大量不稳定角点局部地图抖动反而加剧。nFeatures 不是越大越好1000 到 1500 已经是常规上限再高每帧特征匹配耗时指数上升实时性会垮掉。4. 编译到运行从源码到跑起来看到地图图片序列和配置文件都就绪后进入编译与运行环节。大部分人说“跑 ORB SLAM2”其实就卡在编译这一步因为整个项目要串起多个第三方库缺一个都会在链接阶段报一堆红色错误。这里给一条照抄能过的最小路径再解释运行时每个参数的实际含义。4.1 依赖安装与编译命令照抄能过的最小集合必备依赖有 OpenCV、Eigen3、Pangolin以及项目自带的 DBoW2 和 g2o。在 Ubuntu 环境下安装命令大致是这样sudo apt-get install build-essential cmake git libopencv-dev libeigen3-dev libpangolin-dev cd ORB_SLAM2 chmod x build.sh ./build.shbuild.sh 会依次编译 Thirdparty 下的 DBoW2 和 g2o然后编译整个 ORB SLAM2 主程序。libpangolin-dev 在部分系统的软件源里不存在找不到包时需要先自己编译 Pangolin 源码再将它的库目录加入系统路径。编译过程中如果还没编几步就报错不要急着反复 bash build.sh先看报错发生的子目录和缺失的头文件或库名。比较常见的是 OpenCV 版本与这套旧代码库的接口不匹配出现这类情况时要么把 OpenCV 换成代码库友好的版本要么按报错文件逐个手改接口调用后者对新手不友好。编译成功后会生成几个二进制文件我们关心的是 Examples/Monocular/mono_tum它是单目数据集入口。如果只跑单目不需要额外编译 ROS 版本纯命令行版本就够了。4.2 跑 mono_tum命令里三个参数分别是什么运行命令是固定的三参数结构./Examples/Monocular/mono_tum \ Vocabulary/ORBvoc.txt \ Examples/Monocular/my_camera.yaml \ /home/user/my_sequence第一个参数是词袋模型路径用来在回环检测阶段做图像检索第二个是你的相机配置文件也就是上一章改好的 yaml第三个是包含 rgb.txt 的图片序列目录。ORB SLAM2 启动后先加载词袋然后立刻开始跟踪。终端会周期性打印当前帧号、关键帧数、特征点数量以及追踪状态。如果一直卡在等待图像多半是第三项路径下没有 rgb.txt或者 rgb.txt 里的图片相对路径断掉了。跑起来以后如果画面里特征点一直在跳动但迟迟不初始化不要马上改代码先确认第一帧和第二帧之间有没有平移分量。单目初始化本质上是在两帧之间做本质矩阵或单应矩阵估计纯旋转时这两者都退化初始化过不去是数学上必然的不是系统坏了。4.3 跑完以后轨迹文件去哪里了画面窗口怎么看运行时会有两个窗口一个是当前帧画面叠加了当前跟踪到的特征点另一个是全局地图窗口显示稀疏点云和相机位姿。地图窗口里那些彩色小点就是地图点连起来的线是相机运动轨迹。程序正常退出后会在当前目录输出关键帧轨迹文件里面每一行是时间戳、平移 xyz、四元数 xyzw。这份轨迹就是后续精度验证的输入。提醒一点单目方案的轨迹没有绝对尺度输出的“米”只是相对单位。拿它当二维路径示意图没问题但要和真实物理距离对比必须先通过已知长度的运动或者标定板恢复尺度。这是单目的固有性质不是配置错误。5. 跑自己的图片序列数据集最容易踩的 5 个坑现象、原因与解决下面这些坑是我自己在跑自采序列和帮同事排查时反复见过的每一条都按现象、原因、解决展开。提前知道能省出一整天调试时间。5.1 坑一运动模糊让特征点掉到零追踪直接丢现象运行几十帧后特征点数量骤降到个位数追踪线程反复重定位轨迹中断。 原因拍摄时相机移动速度过快或对焦没锁定画面产生运动模糊FAST 角点检测器在这种画面上几乎提取不到角点。 解决拍摄阶段让相机慢速平移并固定对焦如果素材已经拍完抽帧时不要额外压缩别用低码率格式。更稳妥的办法是宁可少抽帧也要保证每帧画面清晰。模糊不是玄学它直接摧毁整个特征提取管线。5.2 坑二相机内参顺序写错地图越到边缘越歪现象初始化正常但地图从一开始就带弧度走过的回环闭合不上误差越来越大。 原因标定结果和 yaml 参数没对齐。最常见的是把 OpenCV 输出的 k1 k2 p1 p2 k3 五个系数全填进去或者把 fx 和 fy 填反。 解决逐个核对 yaml 里的 fx fy cx cy 与标定输出一致畸变只保留前四项不要带 k3。核对方法很简单用标定脚本里任意一张图做一次 undistort如果 yaml 顺序正确校正后棋盘格边缘应该是直线不然会残留桶形或枕形畸变。5.3 坑三时间戳间隔和真实帧率对不上轨迹整体漂移现象运行过程看起来一切正常但轨迹整体弯曲回环检测一直不触发。 原因图片序列来自多个视频拼接或者抽帧时用的 fps 和生成 rgb.txt 时写的间隔不一致导致运动模型里的速度估计失真。 解决全部素材统一用 ffmpeg 按固定 fps 抽帧rgb.txt 严格按 1/fps 递增不要手工拼接不同来源的图片。时间戳这一步偷懒后面所有数值输出都是不可信的。5.4 坑四画面纹理太稀疏初始化永远过不去现象启动后一直打印初始化尝试但始终不产生第一对关键帧。 原因单目初始化需要两帧间有足够匹配点和视差。白墙、平整桌面、天空这类低纹理画面ORB 提取不到足够角点视差估计退化。 解决拍摄时让画面里保留桌椅角、纸箱、树干等有明显棱角的物体已经拍完的素材尝试降低 ORBextractor.iniThFAST 到 12 以下。同时注意启动时不要原地转圈先平移一段距离再开始正式运动。 如果还想抢救极低纹理素材可以在画面局部贴几张带纹理的纸或海报再重拍比调参更有效。5.5 坑五路径带中文或空格加载数据集直接失败现象运行命令没有报错但加载图片时频繁打不开文件或者 rgb.txt 解析异常。 原因ORB SLAM2 内部拼接图片路径时对特殊字符处理不完善中文目录或含空格路径会触发加载失败。 解决数据集目录、配置文件路径、工作目录全部使用纯英文且不含空格。这个坑看起来低级但在从 Windows 共享目录或网盘同步目录下跑时经常出现顺手把数据集复制到本地纯英文路径能省很多事。6. 用轨迹评估和地图保存验证结果跑通只是第一步画面不飘、地图看起来像样不代表轨迹精度达标。我习惯用 evo 工具把输出的轨迹和一个参考值做对比用数字替代“感觉”。6.1 用 evo 对比轨迹精度假设程序输出的关键帧轨迹文件叫 KeyFrameTrajectory.txt你手里有一份通过标定板或已知运动得到的真值轨迹可以这样算绝对位姿误差evo_ape mono KeyFrameTrajectory.txt groundtruth.txt -a这条命令的含义是计算两条轨迹的绝对位姿误差-a 表示先做位姿对齐再计算。因为单目轨迹没有尺度直接对比毫无意义必须先对齐才能看出形状和走向是否一致。没有真值轨迹时退而求其次看两件事轨迹闭合后首尾位置是否重合以及全局地图中同一面墙的点云是否叠成一条线。这两项全过至少说明数据链路是干净的。6.2 保存地图与固定参数的习惯想把这个地图留给后续使用常见做法是给源码加一个保存接口在程序退出前把当前地图序列化到文件。具体实现可以查看源码里的 Map 存储相关类在退出流程里调用一次保存逻辑。跑自己的图片序列数据集时我现在的习惯是每次实验把 yaml 的 nFeatures、FAST 阈值、帧率三个值记下来同一个场景固定参数重跑这样改算法时才有可对比的基线。地图保存和参数记录这件事越早养成习惯后面做算法改动对比时就越省力算是我从多次重复调参里攒下来的血泪经验。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。