news 2026/10/15 18:24:23

TUM、KITTI、EuRoC三大SLAM数据集选型与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TUM、KITTI、EuRoC三大SLAM数据集选型与避坑指南

简介:这份文档面向SLAM、自动驾驶与微型无人机方向的研究者和学生,系统梳理了TUM RGB-D、KITTI与EuRoC三大主流数据集的采集平台、数据格式与评价准则,帮助读者快速建立对多传感器数据集的整体认知,解决入门选型与格式理解上的困惑。资源包内含1个docx文档,压缩包约1.93MB,以文字整理为主,便于离线查阅与笔记归档。内容覆盖TUM数据集的彩色图与深度图存储规范、深度值缩放关系、groundtruth轨迹的位姿格式,以及ATE与RPE两类评价指标和点云生成脚本的用途;同时介绍KITTI采集车所搭载的GPS/IMU、激光扫描仪与灰度彩色相机配置,以及raw data、object、tracking等数据组织方式,并简述EuRoC中相机、IMU与GPS的融合数据特点。目前已有9572人学习下载,适合需要横向对比数据集、准备实验或撰写综述的读者参考。

1. 三个数据集选错一个,整条 SLAM 链路都在白跑

做视觉惯性里程计、激光雷达建图或者多传感器融合的人,几乎都绕不开 TUM、KITTI、EuRoC 这三个名字。它们不是"随便挑一个跑跑"的玩具数据,而是各自代表了一类传感器配置、一类运动模式和一类评测标准。选错了,你会发现算法在某个数据集上指标漂亮得不行,换一个直接崩掉,回头查半天代码,问题其实出在数据本身——时间戳对不齐、外参坐标系定义不同、真值频率和传感器频率差一个量级。这篇笔记把这三个数据集从"是什么"讲到"怎么用、参数怎么设、坑在哪",面向的是已经动手写代码、准备跑通第一条轨迹的从业者。读完你应该能判断:手头这个任务该用哪个数据集,下载哪几个序列,怎么把时间戳和真值对齐,以及为什么你的轨迹评估结果和别人差那么多。

2. TUM、KITTI、EuRoC 到底差在哪:传感器配置与适用场景对照

2.1 三者的传感器配置与坐标系定义

TUM RGB-D 数据集的核心是 RGB-D 相机,输出彩色图、深度图和相机轨迹真值,运动以手持慢速为主,场景是室内桌面和房间。它的真值来自运动捕捉系统,精度高但覆盖范围小。KITTI 的核心是车载平台:双目灰度相机、彩色相机、64 线激光雷达、GPS/IMU,运动是城市道路和高速公路的车辆行驶,速度快、尺度大,真值来自 GPS/IMU 融合。EuRoC 的核心是微型飞行器:双目灰度相机加 IMU,运动是室内房间和工业环境的飞行,包含明显的剧烈旋转和振动,真值来自激光跟踪仪和运动捕捉系统。

坐标系定义是第一个容易翻车的地方。TUM 的相机坐标系遵循 OpenCV 约定:x 向右、y 向下、z 向前。KITTI 的相机坐标系同样是 x 向右、y 向下、z 向前,但激光雷达坐标系是 x 向前、y 向左、z 向上,两者之间有一个固定的旋转外参。EuRoC 的相机坐标系是 x 向右、y 向下、z 向前,IMU 坐标系是 x 向前、y 向左、z 向上,相机和 IMU 之间的外参在标定文件里给出。如果你直接把 KITTI 的激光点云按相机坐标系读进去,建出来的地图会是躺着的。

数据集主传感器运动模式真值来源典型用途
TUMRGB-D 相机手持慢速运动捕捉室内稠密建图、RGB-D SLAM
KITTI双目+激光+GPS/IMU车载快速GPS/IMU 融合室外里程计、激光建图、目标检测
EuRoC双目+IMU飞行剧烈激光跟踪+动捕VIO、视觉惯性紧耦合

2.2 时间戳格式与真值频率的差异

TUM 的时间戳是浮点秒,单位秒,精度到小数点后六位,真值文件里每行是timestamp tx ty tz qx qy qz qw。KITTI 的时间戳是整数,单位是帧号或者微秒,取决于你读的是哪个文件,真值文件里每行是 12 个数的变换矩阵,按行展开。EuRoC 的时间戳是整数纳秒,真值文件里每行是timestamp px py pz qw qx qy qz,注意四元数顺序和 TUM 不一样。

真值频率也不一样。TUM 的真值频率通常和图像帧率一致或者更高,KITTI 的真值频率是 10 Hz,而激光雷达是 10 Hz、相机是 15 Hz,EuRoC 的真值频率是 200 Hz,IMU 是 200 Hz,相机是 20 Hz。这意味着你在做时间对齐时,不能假设所有传感器都是同一频率,必须做插值或者最近邻匹配。

提示:EuRoC 的四元数顺序是qw qx qy qz,TUM 是qx qy qz qw,KITTI 是矩阵。写解析代码时先确认顺序,否则轨迹会莫名其妙地翻转。

2.3 选型决策:什么任务该用哪个数据集

如果你的任务是室内稠密建图、RGB-D SLAM、或者需要彩色图和深度图做语义融合,TUM 是首选。它的场景小、运动慢,适合验证前端跟踪和稠密重建。如果你的任务是室外激光雷达里程计、双目视觉里程计、或者需要大尺度场景做回环检测,KITTI 更合适。它的运动速度快、场景大,能暴露尺度漂移和回环失败的问题。如果你的任务是视觉惯性紧耦合、IMU 预积分、或者需要剧烈运动下的鲁棒性验证,EuRoC 是标准选择。它的 IMU 噪声和飞行振动是很多 VIO 算法的试金石。

常见做法是:先在 TUM 上跑通前端,确认特征跟踪和深度关联没问题;再换到 EuRoC 验证 IMU 预积分和初始化;最后上 KITTI 测大尺度下的漂移和回环。反过来做也行,但如果你一上来就用 KITTI 调 VIO,大概率会被尺度和时间戳问题卡住。

3. 把 TUM 跑通:从下载到轨迹对齐的最小流程

3.1 下载与目录结构确认

TUM 的 RGB-D 数据集按序列发布,每个序列是一个压缩包,解压后包含rgb/、depth/、groundtruth.txt、associations.txt等文件。associations.txt是官方给出的 RGB 和深度图的时间戳匹配文件,每行是rgb_timestamp rgb_path depth_timestamp depth_path。如果你不用这个文件,自己按时间戳最近邻匹配,可能会因为深度图和彩色图的时间戳不完全一致而丢帧。

# 假设下载的是 fr1/xyz 序列 mkdir -p tum_fr1_xyz tar -xzf rgbd_dataset_freiburg1_xyz.tgz -C tum_fr1_xyz ls tum_fr1_xyz # 应该看到 rgb/ depth/ groundtruth.txt associations.txt 等

逻辑说明:TUM 的压缩包解压后目录名可能带rgbd_dataset_前缀,脚本里要按实际名字改。associations.txt是官方对齐结果,优先用它,不要自己重新匹配。

3.2 用 Python 读取真值并转成 TUM 格式

TUM 真值文件每行是timestamp tx ty tz qx qy qz qw,四元数顺序是qx qy qz qw。如果你要喂给一个期望qw qx qy qz的库,需要转换。

import numpy as np def read_tum_groundtruth(path): """读取 TUM 格式真值,返回时间戳和 4x4 变换矩阵列表""" data = [] with open(path, 'r') as f: for line in f: if line.startswith('#'): continue parts = line.strip().split() if len(parts) < 8: continue t = float(parts[0]) tx, ty, tz = map(float, parts[1:4]) qx, qy, qz, qw = map(float, parts[4:8]) # 四元数转旋转矩阵 R = np.array([ [1-2*(qy*qy+qz*qz), 2*(qx*qy-qz*qw), 2*(qx*qz+qy*qw)], [2*(qx*qy+qz*qw), 1-2*(qx*qx+qz*qz), 2*(qy*qz-qx*qw)], [2*(qx*qz-qy*qw), 2*(qy*qz+qx*qw), 1-2*(qx*qx+qy*qy)] ]) T = np.eye(4) T[:3, :3] = R T[:3, 3] = [tx, ty, tz] data.append((t, T)) return data

参数说明:path是真值文件路径。返回的data是列表,每个元素是(timestamp, T)。注意 TUM 的四元数顺序是qx qy qz qw,如果你直接按qw qx qy qz读,旋转矩阵会错。

3.3 轨迹评估:用 evo 做绝对位姿误差

轨迹评估是验证算法是否跑通的关键一步。常见做法是用evo工具,它支持 TUM、KITTI、EuRoC 格式的轨迹文件。

# 安装 evo pip install evo --upgrade --no-binary evo # 评估 TUM 格式轨迹,输出绝对位姿误差 evo_ape tum groundtruth.txt estimated.txt --align --plot --save_results results.zip

逻辑说明:--align会做轨迹对齐,因为估计轨迹和真值轨迹的起点可能不一致。--plot会画出轨迹对比图。--save_results把结果存成 zip,里面包含误差统计。如果你不做对齐,APE 会非常大,因为坐标系原点不同。

注意:TUM 的真值频率可能高于估计轨迹频率,evo会自动做时间戳匹配,但如果你的估计轨迹时间戳格式不对,匹配会失败。确保估计轨迹也是timestamp tx ty tz qx qy qz qw格式。

4. KITTI 的坑:激光雷达和相机外参、时间戳、真值频率

4.1 激光雷达与相机的外参矩阵怎么用

KITTI 的激光雷达和相机之间有一个固定的外参矩阵,通常在calib.txt里。这个矩阵是 3x4 的,表示从激光雷达到相机的变换。如果你要把激光点投影到图像上,需要先转到相机坐标系,再用相机内参投影。

import numpy as np def project_lidar_to_image(points_lidar, calib_path): """把激光点投影到图像,points_lidar 是 Nx3""" calib = {} with open(calib_path, 'r') as f: for line in f: key, value = line.strip().split(':') calib[key] = np.array([float(x) for x in value.split()]) # P 是 3x4 相机投影矩阵,R0 是 3x3 校正旋转,Tr 是 3x4 激光到相机 P = calib['P2'].reshape(3, 4) R0 = calib['R0_rect'].reshape(3, 3) Tr = calib['Tr_velo_to_cam'].reshape(3, 4) # 激光点转到相机坐标系 points_cam = (Tr @ np.hstack([points_lidar, np.ones((len(points_lidar), 1))]).T).T # 校正 points_rect = (R0 @ points_cam[:, :3].T).T # 投影 points_img = (P @ np.hstack([points_rect, np.ones((len(points_rect), 1))]).T).T points_img = points_img[:, :2] / points_img[:, 2:3] return points_img

参数说明:calib_path是 KITTI 的标定文件路径。P2是左彩色相机的投影矩阵,R0_rect是校正旋转,Tr_velo_to_cam是激光到相机的变换。注意Tr_velo_to_cam是 3x4,最后一行是 0 0 0 1,代码里用np.hstack补了齐次坐标。

4.2 时间戳对齐:为什么你的轨迹和真值差了几十米

KITTI 的时间戳文件在times.txt里,每行是一个浮点数,单位是秒。真值文件在poses.txt里,每行是 12 个数,按行展开的 3x4 变换矩阵。问题在于:times.txt的时间戳是相对于序列开始的,而poses.txt的真值频率是 10 Hz,两者不一定一一对应。如果你直接按行号匹配,会错位。

常见做法是:先读times.txt,再读poses.txt,然后按时间戳最近邻匹配。如果times.txt有 1000 行,poses.txt有 100 行,你需要为每个时间戳找到最近的位姿。

import numpy as np def align_kitti_poses(times_path, poses_path): """按时间戳最近邻匹配 KITTI 位姿""" times = np.loadtxt(times_path) poses = np.loadtxt(poses_path) # poses 每行 12 个数,转成 3x4 poses = poses.reshape(-1, 3, 4) aligned = [] for t in times: # 真值频率 10 Hz,时间戳是 0, 0.1, 0.2, ... idx = int(round(t / 0.1)) idx = min(idx, len(poses) - 1) aligned.append((t, poses[idx])) return aligned

参数说明:times_path是times.txt路径,poses_path是poses.txt路径。这里假设真值频率严格是 10 Hz,如果实际有抖动,需要用np.searchsorted做最近邻。

4.3 真值频率与传感器频率不一致时的处理

KITTI 的相机是 15 Hz,激光雷达是 10 Hz,真值是 10 Hz。如果你做视觉里程计,估计轨迹的频率是 15 Hz,而真值是 10 Hz,评估时需要把估计轨迹插值到真值时间戳,或者把真值插值到估计时间戳。evo支持自动插值,但你需要确保时间戳格式正确。

提示:KITTI 的真值文件poses.txt没有时间戳列,时间戳在times.txt里。如果你只下载了poses.txt,需要自己按 10 Hz 生成时间戳。

5. EuRoC 的避坑与排查:四元数顺序、IMU 噪声、时间偏移

5.1 四元数顺序写反,轨迹直接翻转

EuRoC 的真值文件state_groundtruth_estimate0/data.csv每行是timestamp px py pz qw qx qy qz vx vy vz ...。注意四元数顺序是qw qx qy qz,和 TUM 的qx qy qz qw不一样。如果你按 TUM 的顺序读,旋转矩阵会错,轨迹会翻转或者乱转。

现象:轨迹评估时 APE 很大,可视化时轨迹形状完全不对。原因:四元数顺序读错。解决:确认文件头或者文档,EuRoC 是qw qx qy qz。

5.2 IMU 噪声参数设错,预积分直接发散

EuRoC 的 IMU 噪声参数在sensor.yaml里,包括gyro_noise_density、gyro_random_walk、acc_noise_density、acc_random_walk。这些参数是 VIO 算法初始化的关键。如果你用默认值或者随便填,预积分会发散。

现象:VIO 初始化失败,或者轨迹跑几秒后飞掉。原因:IMU 噪声参数和实际数据不匹配。解决:从sensor.yaml里读实际参数,不要用经验值。

# EuRoC sensor.yaml 片段 imu0: gyro_noise_density: 1.6968e-04 gyro_random_walk: 1.9393e-05 acc_noise_density: 2.0000e-03 acc_random_walk: 3.0000e-03

参数说明:gyro_noise_density单位是rad/s/sqrt(Hz),acc_noise_density单位是m/s^2/sqrt(Hz)。这些值直接影响预积分的协方差传播。

5.3 相机和 IMU 时间偏移没补偿,尺度估计偏小

EuRoC 的相机和 IMU 之间存在时间偏移,通常在sensor.yaml里有timeshift_cam_imu参数。如果你忽略这个偏移,VIO 的尺度估计会偏小,轨迹会缩水。

现象:轨迹评估时尺度误差明显,或者初始化时尺度估计不稳定。原因:相机和 IMU 时间戳没有对齐。解决:在读取数据时,把相机时间戳加上timeshift_cam_imu,或者把 IMU 时间戳减去。

5.4 真值频率 200 Hz,评估时降采样没做对

EuRoC 的真值是 200 Hz,而你的估计轨迹可能是 20 Hz。评估时如果直接把 200 Hz 真值和 20 Hz 估计轨迹做最近邻匹配,误差会偏大,因为真值的高频信息被浪费了。

现象:APE 比预期大,但轨迹看起来还行。原因:真值和估计轨迹频率不匹配,最近邻匹配引入了额外误差。解决:先把真值降采样到估计轨迹的频率,或者用evo的--t_max_diff参数控制最大时间差。

注意:evo默认会做时间戳匹配,但如果频率差太大,匹配上的点可能很少。建议先把真值降采样到和估计轨迹相近的频率。

6. 三个数据集混着用:统一格式、统一评估、统一习惯

6.1 写一个统一的轨迹读取接口

三个数据集的格式不一样,但你可以写一个统一的读取接口,把 TUM、KITTI、EuRoC 都转成(timestamp, 4x4 matrix)的列表。这样评估代码只需要写一次。

def load_trajectory(path, fmt): """统一读取轨迹,fmt 是 'tum'、'kitti' 或 'euroc'""" if fmt == 'tum': return read_tum_groundtruth(path) elif fmt == 'kitti': times = np.loadtxt(path.replace('poses.txt', 'times.txt')) poses = np.loadtxt(path).reshape(-1, 3, 4) result = [] for t, p in zip(times, poses): T = np.eye(4) T[:3, :4] = p result.append((t, T)) return result elif fmt == 'euroc': data = np.loadtxt(path, delimiter=',', skiprows=1) result = [] for row in data: t = row[0] * 1e-9 # 纳秒转秒 T = np.eye(4) T[:3, 3] = row[1:4] qw, qx, qy, qz = row[4:8] # 四元数转旋转矩阵,注意顺序 R = np.array([ [1-2*(qy*qy+qz*qz), 2*(qx*qy-qz*qw), 2*(qx*qz+qy*qw)], [2*(qx*qy+qz*qw), 1-2*(qx*qx+qz*qz), 2*(qy*qz-qx*qw)], [2*(qx*qz-qy*qw), 2*(qy*qz+qx*qw), 1-2*(qx*qx+qy*qy)] ]) T[:3, :3] = R result.append((t, T)) return result

参数说明:path是文件路径,fmt是格式字符串。EuRoC 的时间戳是纳秒,需要乘1e-9转秒。四元数顺序是qw qx qy qz,和 TUM 不同。

6.2 用 evo 统一评估三个数据集

evo支持 TUM、KITTI、EuRoC 格式,但你需要把轨迹保存成对应格式。常见做法是:统一转成 TUM 格式,然后用evo_ape tum评估。

# 把估计轨迹和真值都转成 TUM 格式 python convert_to_tum.py estimated.txt groundtruth.txt # 评估 evo_ape tum groundtruth_tum.txt estimated_tum.txt --align --plot

逻辑说明:convert_to_tum.py是你自己写的转换脚本,把 KITTI 或 EuRoC 格式转成timestamp tx ty tz qx qy qz qw。--align做轨迹对齐,--plot画图。

6.3 我的习惯:先跑 TUM,再上 EuRoC,最后 KITTI

我自己的习惯是:先在 TUM 上跑通前端,确认特征跟踪、深度关联、轨迹输出没问题;再换到 EuRoC 验证 IMU 预积分和初始化,因为 EuRoC 的 IMU 噪声和飞行振动会暴露很多问题;最后上 KITTI 测大尺度下的漂移和回环。这个顺序的好处是,每一步只引入一个新的变量,出问题时容易定位。如果你一上来就用 KITTI 调 VIO,尺度和时间戳问题会混在一起,排查起来很痛苦。

还有一个习惯是:每次换数据集,先跑一遍纯视觉里程计,不加 IMU,看看轨迹能不能大致对上。如果纯视觉都跑不通,加 IMU 只会更乱。这个习惯帮我省了很多后悔药。

希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 18:21:53

为什么TechSpar题库不是固定题单?动态出题底座的核心设计深度揭秘

【免费下载链接】TechSpar 一个持续进化的面试训练系统。在线体验地址&#xff1a;https://techspar.cn 项目地址&#xff1a; https://gitcode.com/gh_mirrors/te/TechSpar 点击查看 免费下载 很多人第一次接触 TechSpar 这套面试训练系统&#xff0c;会下意识把它的「题库」…

作者头像 李华
网站建设 2026/10/15 18:21:25

NMS不是黑箱:目标检测后处理的原理、陷阱与工程优化

1. 为什么NMS不是“调个参数就完事”的黑箱&#xff1f;目标检测模型输出成百上千个边界框&#xff0c;但真实场景里一辆车只该有一个框。NMS&#xff08;Non-Maximum Suppression&#xff0c;非极大值抑制&#xff09;就是那个“裁缝”&#xff0c;负责把重叠的、冗余的、低置…

作者头像 李华
网站建设 2026/10/15 18:21:08

交流电路分析核心:相量图、RLC谐振与功率因数补偿

简介&#xff1a;本资源为《电工电子技术&#xff08;第2版&#xff09;》教材的课后习题答案PDF&#xff0c;主要面向电气工程、自动化及相关专业本专科学生&#xff0c;用于巩固交流电路、相量法、阻抗与电路分析等核心内容。资料内按习题顺序整理了解答步骤与关键知识点解析…

作者头像 李华
网站建设 2026/10/15 18:20:57

多尺度梯度GAN:解决生成器深层训练不稳定的工程实践

1. 从一张“糊脸”说起&#xff1a;为什么多尺度梯度值得关注如果你跑过早期的生成对抗网络&#xff0c;大概率见过这样的场景&#xff1a;训练到几万步&#xff0c;生成器终于能画出人脸的轮廓了&#xff0c;但五官像被水泡过一样糊成一团&#xff1b;再训练下去&#xff0c;轮…

作者头像 李华
网站建设 2026/10/15 18:19:45

Kitex v0.16.0 深度解析:流式事件追踪体系与 Recv 超时精细化控制

后端RPC框架微服务服务注册发现负载均衡 【免费下载链接】kitex Go RPC framework with high-performance and strong-extensibility for building micro-services. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ki/kitex 点击查看 免费下载 Kitex v0.16.0 是围绕 St…

作者头像 李华