ORB-SLAM2单目数据集准备:TUM格式图像序列与yaml标定配置指南

发布时间:2026/10/16 3:23:12
ORB-SLAM2单目数据集准备:TUM格式图像序列与yaml标定配置指南 简介本资源是一份面向SLAM初学者与机器人视觉开发者的实践指南聚焦如何使用ORB SLAM2系统处理自采图像序列完成定位与建图任务解决个人数据集无法直接运行官方SLAM框架的常见痛点。压缩包共4个文件2个Python脚本、1个MP4视频、1个txt配置文件总大小4.38MB其中myvideo.mp4用于演示原始视频采集file.py与rgb_sep.py分别实现帧提取与rgb.txt自动生成txt文件为已配好的时间戳索引文件结构简洁、开箱即用。已有5378人学习下载适合希望跳过环境配置与数据预处理繁琐环节、快速验证ORB SLAM2在自定义场景中效果的学习者。读者可直接复现从视频→图片序列→时间戳文件→SLAM运行的全流程获得可调试的脚本工具链、标准rgb.txt生成逻辑及典型目录组织范式显著降低视觉SLAM入门门槛。1. 用 ORB-SLAM2 跑自己的图片序列数据集不是调个参数就能跑通而是要亲手把图像喂进黑匣子并听懂它的报错声你手头有一组按时间顺序拍的 JPG 序列比如手机拍的走廊、实验室桌面、楼梯间想试试 SLAM 是不是真能“边走边建图”但 clone 完 ORB-SLAM2 仓库后./Examples/Monocular/mono_tum一跑就 core dumpmono_euroc报错Could not load camera parameters甚至mono_kitti直接提示No images loaded——这根本不是环境没配好而是你还没把 ORB-SLAM2 当成一个严格依赖输入结构的编译时绑定系统来对待。它不接受“差不多的图片”“大概对的路径”“看着像的 yaml”它只认三样东西严格命名的图像序列、毫米级精度的相机内参、与帧率完全同步的时间戳文件。本篇不讲李群李代数不推导重投影误差只带你从零开始把你自己拍的 200 张 JPG 变成 ORB-SLAM2 能吞下去、能吐出轨迹、能生成点云的合法输入。适合刚跑通 TUM/EuRoC 示例、正对着自己相机拍的图发愁的算法工程师、机器人方向研究生和嵌入式视觉开发者。核心就一句话SLAM 不是魔法是精密仪器你的数据不是素材是标定过的工件。2. 数据准备为什么必须用 TUM 格式因为 ORB-SLAM2 的 Monocular 模块在编译期就锁死了输入解析逻辑ORB-SLAM2 的单目模式mono_tum并非通用图像加载器其源码中Tracking.cc和System.cc明确调用TUMDataset类进行初始化而该类在Thirdparty/DBoW2/DBoW2/TUMDataset.h中硬编码了路径拼接规则与文件名正则匹配逻辑。这意味着你不能靠改命令行参数绕过格式限制必须让数据长成它认的长相。下面分三步拆解真实落地动作——不是“建议”是make时链接进二进制的铁律。2.1 图像重命名必须满足123456789.png这种纯数字扩展名格式且严格递增ORB-SLAM2 的TUMDataset构造函数中通过std::stoll(filename.stem().string())将文件名转为 long long 类型时间戳单位纳秒。若你用IMG_001.jpg、frame-0001.png或left_00001.jpgstoll会返回 0导致所有图像被赋予同一时间戳后续帧间匹配直接失效。更致命的是TUMDataset::LoadImages()内部用std::maplong long, std::string存储路径重复时间戳会覆盖前序图像。提示不要用rename命令暴力重命名需确保数字严格递增且无间隙。间隙本身不致命但若跳变过大如从1000直接到500000会导致TUMDataset::GetImage()在二分查找时越界访问。# ✅ 正确做法用 Python 脚本生成连续数字命名假设原始图在 ./raw/ 下 cd ./raw python3 -c import os, glob, re files sorted(glob.glob(*.jpg) glob.glob(*.jpeg) glob.glob(*.png)) for i, f in enumerate(files): ext os.path.splitext(f)[1].lower() new_name f{i1:09d}{ext} # 保证 9 位数字如 000000001.jpg os.rename(f, new_name) print(fRenamed {f} - {new_name}) 这段脚本干了三件事① 统一收集 jpg/jpeg/png② 按字典序排序等价于拍摄时间序前提是相机未重置命名③ 生成000000001.jpg到000000200.jpg的连续序列。注意i1是因 ORB-SLAM2 默认第一帧时间戳为 1非 0避免与内部空指针判断冲突。2.2 时间戳文件rgb.txt不是可选配置而是单目模式的启动开关mono_tum可执行文件启动时强制读取rgb.txt路径由命令行第二参数指定其格式为123456789 rgb/000000001.png 123457890 rgb/000000002.png ...第一列是时间戳单位秒但实际代码中乘以 1e9 转为纳秒第二列是相对于当前目录的图像路径。关键点在于时间戳必须单调递增且相邻帧差值应接近你相机的实际帧率倒数如 30fps → 差值约 0.033s。若你填1 1.png\n2 2.png系统会认为帧率是 1fps特征跟踪窗口、关键帧选取阈值全部错乱。# ✅ 生成合规 rgb.txt假设图像已重命名为 000000001.png ~ 000000200.png目标帧率 20fps cd /path/to/your/dataset mkdir -p rgb mv *.png rgb/ python3 -c import os with open(rgb.txt, w) as f: for i in range(1, 201): # 200 张图 timestamp 1.0 (i-1) * 0.05 # 起始时间 1.0s间隔 0.05s 20fps img_name frgb/{i:09d}.png f.write(f{timestamp:.9f} {img_name}\n) 这里1.0 (i-1)*0.05是工程实践中的安全起始避开时间戳 0部分版本有除零风险且小数位保留 9 位%.9f以匹配 TUM 数据集惯例防止浮点解析歧义。2.3 相机标定文件camera.yaml内参不准尺度漂移畸变不填特征点全飘ORB-SLAM2 单目模式不支持在线标定所有相机模型参数必须在camera.yaml中静态声明。该文件被System.cc中cv::FileStorage加载字段名硬编码为Camera.fx,Camera.fy,Camera.cx,Camera.cy,Camera.k1,Camera.k2,Camera.p1,Camera.p2。漏写任一字段FileStorage::operator[]返回空节点atdouble()抛异常终止。注意k1/k2/p1/p2必须显式写出即使为 0。若你用 OpenCVcalibrateCamera得到[k1,k2,p1,p2,k3]必须丢弃 k3ORB-SLAM2 仅支持径向切向畸变不支持三阶径向。# ✅ 合规 camera.yaml以常见手机广角为例焦距单位像素 %YAML:1.0 Camera.fx: 640.0 Camera.fy: 640.0 Camera.cx: 320.0 Camera.cy: 240.0 Camera.k1: -0.25 Camera.k2: 0.05 Camera.p1: 0.001 Camera.p2: -0.001 Camera.width: 640 Camera.height: 480 Camera.fps: 20.0 Camera.RGB: true关键参数说明Camera.width/height必须与你图像实际分辨率一致可用identify -format %wx%h rgb/000000001.png验证否则cv::Mat创建尺寸错误cv::undistort内存越界Camera.fps仅用于Viewer模块控制显示帧率不影响 SLAM 计算但若设为 0 会导致Viewer::Run()死循环Camera.RGB设为true表示 BGR→RGB 转换OpenCV 默认 BGRSLAM 内部用 RGB若你图像是 RGB 保存如 PIL此处必须false否则颜色通道错乱影响特征提取。3. 编译与运行mono_tum不是万能入口你的数据必须匹配它的编译期绑定路径很多人卡在./Examples/Monocular/mono_tum ./Vocabulary/ORBvoc.txt ./Examples/Monocular/TUM1.yaml ./dataset这条命令上却不知mono_tum可执行文件内部已将TUMDataset的路径解析逻辑固化。它默认期望./dataset/rgb.txt和./dataset/rgb/存在且rgb/下全是*.png。如果你把图像放在./dataset/images/或rgb.txt写成123456789 images/000000001.jpg程序会在TUMDataset::LoadImages()中cv::imread()返回空 Mat随后cv::Mat::empty()检查失败直接throw exception。3.1 确认 ORB-SLAM2 编译版本Monocular 模块是否启用 TUMDataset检查你编译的mono_tum是否真链接了 TUM 支持。进入ORB_SLAM2/Examples/Monocular/目录执行# 查看二进制依赖符号Linux nm -C ./mono_tum | grep -i tum\|dataset # ✅ 正常输出应包含 # U ORB_SLAM2::TUMDataset::TUMDataset(std::__cxx11::basic_stringchar, std::char_traitschar, std::allocatorchar const, std::__cxx11::basic_stringchar, std::char_traitschar, std::allocatorchar const) # U ORB_SLAM2::TUMDataset::LoadImages()若无TUMDataset符号说明你编译时CMakeLists.txt中set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -DUSE_PANGOLIN_VIEWER)后未启用 TUM 支持或Thirdparty/DBoW2/DBoW2/CMakeLists.txt未正确 includeTUMDataset.h。此时必须重新编译cd ORB_SLAM2 rm -rf build mkdir build cd build # ✅ 关键确保 CMake 找到 OpenCV 且定义 TUM_DATASET cmake -DOpenCV_DIR/usr/local/share/opencv4 .. # 路径按你 OpenCV 实际位置调整 make -j$(nproc)提示-DOpenCV_DIR必须指向OpenCVConfig.cmake所在目录通常为/usr/local/share/opencv4或/usr/lib/x86_64-linux-gnu/opencv4否则find_package(OpenCV REQUIRED)失败TUMDataset类无法实例化。3.2 运行命令的四个参数每个都是不可省略的契约./mono_tum voc_path yaml_path dataset_path [save_trajectory_path]这四个参数顺序固定含义如下参数位置含义必填性常见错误1ORBvoc.txt路径✅ 必填放错位置如放成./Vocabulary/目录而非文件文件损坏用md5sum校验官方 SHA2562camera.yaml路径✅ 必填YAML 语法错误如冒号后少空格路径含中文或空格用绝对路径规避3数据集根目录路径✅ 必填误认为是rgb.txt路径目录下无rgb.txt或rgb/子目录4轨迹保存路径可选⚠️ 建议填不填则只显示 Viewer关闭后轨迹丢失路径不存在会静默失败# ✅ 正确运行命令假设所有文件在 /home/user/my_slam_data/ 下 cd ORB_SLAM2/Examples/Monocular/ ./mono_tum \ /home/user/ORB_SLAM2/Vocabulary/ORBvoc.txt \ /home/user/my_slam_data/camera.yaml \ /home/user/my_slam_data/ \ /home/user/my_slam_data/trajectory.txt注意/home/user/my_slam_data/目录结构必须为my_slam_data/ ├── camera.yaml ├── rgb.txt └── rgb/ ├── 000000001.png ├── 000000002.png └── ...3.3 Viewer 窗口行为解读不是卡死是 SLAM 在做三件事启动后出现黑色窗口几秒后显示稀疏点云和绿色轨迹线——这是正常状态。此时后台正在并发执行Tracking 线程对每帧提取 FAST 角点默认 1000 个、计算 BRIEF 描述子、与上一帧匹配光流法初筛 描述子汉明距离精筛Local Mapping 线程对关键帧三角化新地图点、优化局部 BABundle AdjustmentLoop Closing 线程构建词袋数据库检测闭环需至少 20 帧以上才激活。若窗口长期黑屏10s大概率是Tracking线程在Frame::ExtractORB()中卡住——原因通常是图像分辨率过高1280x720导致 ORB 特征提取超时或camera.yaml中Camera.width/height与实际不符引发cv::Mat内存异常。提示按键盘ESC可退出程序会自动保存KeyFrameTrajectory.txt关键帧位姿和FrameTrajectory.txt所有帧位姿到当前目录。这两文件是.txt格式每行tx ty tz qx qy qz qwTUM 格式可直接用evo工具评估精度。4. 避坑五个血泪经验总结每一条都来自真实翻车现场以下是我在调试 12 个不同来源数据集手机、USB 相机、工业相机过程中踩出的硬核坑按发生频率排序附带现象、根因与可立即执行的解决命令。4.1 现象Segmentation fault (core dumped)发生在cv::undistort()调用处原因camera.yaml中Camera.width或Camera.height与图像实际尺寸不一致导致cv::Mat初始化失败后续cv::undistort()对非法 Mat 操作触发 SIGSEGV。解决用identify批量验证图像尺寸并修正camera.yaml# 检查第一张图尺寸 identify -format %wx%h /path/to/rgb/000000001.png # 输出应为 640x480 # 批量检查所有图确保无异常尺寸 find /path/to/rgb/ -name *.png | head -20 | xargs -I{} identify -format %f %wx%h\n {}4.2 现象Viewer 窗口显示“Waiting for images...”后无响应原因rgb.txt中时间戳列被解析为 0如用 Excel 保存时自动转科学计数法1.23E11或时间戳非单调递增如1.0\n0.5\n1.5。TUMDataset::GetImage()内部二分查找失败返回空图像。解决用awk检查rgb.txt时间戳单调性awk {print $1} rgb.txt | awk NR1{prev$1; next} $1prev{print ERROR at line NR : $1 prev; exit 1} {prev$1} || echo Timestamps OK4.3 现象特征点稀少50 个/帧轨迹线断续跳跃原因图像过曝手机自动曝光导致白茫茫一片或过暗低光照下 FAST 无法提取足够角点或camera.yaml中k1/k2符号反了负畸变系数填成正数。解决用ffmpeg批量检查图像亮度分布并用cv2脚本验证畸变校正效果# 检查平均亮度应介于 80~180 ffmpeg -i rgb/000000001.png -vf signalstats -f null - 21 | grep YAVG # 用 Python 快速预览畸变校正需安装 opencv-python python3 -c import cv2, numpy as np img cv2.imread(rgb/000000001.png) K np.array([[640,0,320],[0,640,240],[0,0,1]]) D np.array([-0.25,0.05,0.001,-0.001]) undistorted cv2.undistort(img, K, D) cv2.imshow(undistorted, undistorted); cv2.waitKey(0) 4.4 现象程序启动后立即报错Could not load settings file原因camera.yaml文件编码为 UTF-8 with BOMWindows 记事本默认cv::FileStorage解析失败。解决用file命令检测编码dos2unix清除 BOMfile -i camera.yaml # 若输出包含 charsetutf-8; charsetbom 则需转换 dos2unix camera.yaml # 或用 vim 手动清除vim camera.yaml → :set nobomb → :wq4.5 现象轨迹线呈直线延伸无闭环检测点云发散原因数据集场景纹理贫乏如纯白墙壁、玻璃幕墙或相机运动过快帧间位移 30 像素导致特征匹配失败系统退化为纯里程计。解决强制降低帧率并增加关键帧阈值在camera.yaml末尾添加需重新编译mono_tum# 添加到 camera.yaml 底部ORB-SLAM2 v1.0 兼容 ThDepth: 40.0 # 深度滤波阈值提高可减少误匹配 KeyFrameFrequency: 1.0 # 每秒最多插入 1 个关键帧原默认 0.5注意KeyFrameFrequency修改需重新编译因其在Tracking.cc中硬编码为mKeyFrameCounter 15对应 30fps 下 0.5s 一帧直接改 YAML 无效。5. 轨迹验证与点云导出用 evo 和 COLMAP 把文本轨迹变成可量化的三维证据跑出KeyFrameTrajectory.txt只是第一步真正决定你数据是否合格的是轨迹的平滑度、尺度一致性与闭环精度。这里不讲理论只给三个命令让你 5 分钟内拿到量化报告。5.1 用 evo 评估轨迹绝对精度ATEevo是目前最主流的 SLAM 轨迹评估工具支持 TUM、KITTI、EuRoC 格式。先安装推荐 pippip3 install evo --upgrade --no-binary evo evo_config set plot_seaborn_style whitegrid然后将你的轨迹与真值对齐若无真值跳过--ref用evo_ape tum看相对精度# ✅ 假设有真值轨迹 groundtruth.txt同格式 evo_ape tum groundtruth.txt KeyFrameTrajectory.txt -va --plot --plot_mode xyz # ✅ 若无真值评估自身连续性看 APE 的标准差 evo_rpe tum KeyFrameTrajectory.txt --delta 1 --delta_unit s --plot关键看输出中的rmse均方根误差和std标准差rmse 0.1m优秀室内小场景rmse 0.1~0.3m可用需检查是否某段突变rmse 0.5m数据或标定严重问题重点查camera.yaml和rgb.txt5.2 从 KeyFrameTrajectory.txt 提取点云用 Python 脚本生成 PLY 文件ORB-SLAM2 自身不导出稠密点云但所有关键帧的地图点MapPoint坐标都存在内存中。我们可利用KeyFrameTrajectory.txt中的位姿结合 ORB-SLAM2 的MapPoint存储逻辑MapPoint.h中mWorldPos成员用离线方式重建。但更简单的方法是用轨迹驱动 COLMAP 进行增量式 SfM复用你已有的图像和位姿先验。# ✅ 步骤1) 用轨迹生成 COLMAP cameras.txt / images.txt2) 运行 COLMAP mapper python3 -c import numpy as np # 读取 KeyFrameTrajectory.txtTUM 格式tx ty tz qx qy qz qw data np.loadtxt(KeyFrameTrajectory.txt) # COLMAP images.txt 格式IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME with open(images.txt, w) as f: for i, row in enumerate(data): tx, ty, tz, qx, qy, qz, qw row # COLMAP 使用 Hamilton 乘法顺序ORB-SLAM2 的 qw,qx,qy,qz 即可直接用 f.write(f{i1} {qw} {qx} {qy} {qz} {tx} {ty} {tz} 1 rgb/{i1:09d}.png\n) f.write(\n) # COLMAP 要求空行分隔 # 生成 cameras.txt单相机模型 echo 1 PINHOLE 640 480 640 640 320 240 cameras.txt # 运行 COLMAP需提前安装 COLMAP colmap feature_extractor --database_path database.db --image_path rgb/ --ImageReader.single_camera 1 colmap mapper --database_path database.db --image_path rgb/ --export_path . --Mapper.init_min_tri_angle 4.0运行后sparse/0/points3D.bin即为稠密点云可用ply工具转换colmap model_converter --input_path sparse/0 --output_path points3D.ply --output_type PLY5.3 点云质量自检三个命令快速定位问题点云不是越多越好关键看分布合理性# 1) 检查点云数量应 5000 个有效点 pcl_info points3D.ply | grep points # 2) 检查空间范围Z 坐标应集中在 0.5~5.0 米若全在 Z0 说明尺度崩溃 pcl_stats points3D.ply | grep Z: # 3) 可视化用 CloudCompare 或 MeshLab 打开 points3D.ply看是否呈现走廊/房间结构若点云稀疏且集中在图像平面Z≈0说明单目 SLAM 尺度不可观需检查①camera.yaml中fx/fy是否小了 10 倍常见错误② 场景缺乏远近纹理如全是平行线③rgb.txt时间戳间隔过大0.1s导致三角化基线不足。从那以后我每次拿到新数据都强制走一遍这三步identify验尺寸 →awk查时间戳 →evo_ape看 rmse。不是为了炫技是避免花 3 小时调参数最后发现是camera.yaml里cx写成了cy。SLAM 的魅力在于它诚实得残酷——你给它什么数据它就还你什么结果不多一分不少一毫。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询