4、数据输入格式:支持的数据类型与文件结构解析

做轨迹评估,第一步就是喂数据。但说实话,我见过太多人在这第一步就栽跟头了。数据格式不对,后面所有分析都是白搭。今天咱们就聊聊轨迹评估工具支持的那几种主流数据格式——TUM、KITTI、EuRoC,以及怎么避开那些常见的坑。

4.1 三种主流数据格式概览

目前业内用得最多的,就是这三种格式。我个人习惯把它们分成两类:带时间戳的和不带时间戳的。你想想看,时间戳这东西,直接决定了你能不能做时间对齐。

格式 来源 核心特点 时间戳
TUM 慕尼黑工业大学 每行包含时间戳+位姿 有(浮点数,单位秒)
KITTI 卡尔斯鲁厄理工学院 纯位姿数据,无时间戳 无
EuRoC 苏黎世联邦理工学院 时间戳+位姿,但格式略有不同 有(整数,单位纳秒)

核心要点: 评估工具能不能跑,90%取决于你的数据格式对不对。剩下10%是路径对不对。

4.2 TUM格式详解

TUM格式是我用得最多的,也是评估工具默认支持的格式。它的结构其实很简单,每行7个数字:

# 这是注释行,工具会自动忽略
timestamp tx ty tz qx qy qz qw

举个例子:

1403715273.542 1.234 2.345 3.456 0.123 0.234 0.345 0.912
1403715273.643 1.245 2.356 3.467 0.124 0.235 0.346 0.913

这里要注意几个细节:

  • 时间戳:单位是秒,浮点数。我见过有人用整数秒,结果对齐全乱了
  • 平移:tx, ty, tz,单位是米
  • 旋转:四元数 qx, qy, qz, qw,必须是单位四元数

我的小技巧: 我习惯在文件开头加一行注释,写上数据来源和传感器类型。虽然工具不读,但自己回头看的时候特别有用。

4.3 KITTI格式详解

KITTI格式就有点不一样了。它没有时间戳,每行是一个3x4的变换矩阵:

r11 r12 r13 tx r21 r22 r23 ty r31 r32 r33 tz

说白了,就是把旋转矩阵和平移向量拼在一行里:

0.999 0.012 -0.015 1.234 -0.011 0.999 0.013 2.345 0.015 -0.013 0.999 3.456

嗯,这里要注意:

  • 没有时间戳,所以评估时只能按顺序逐帧对比
  • 矩阵必须合法,旋转部分必须是正交矩阵
  • 12个数字,一个都不能少

警告: 我曾经遇到过一个数据集,旋转矩阵的行列式是-1,结果评估出来的误差大得离谱。后来才发现是坐标系定义反了。

4.4 EuRoC格式详解

EuRoC格式跟TUM有点像,但时间戳是整数纳秒:

timestamp_ns, tx, ty, tz, qx, qy, qz, qw

实际数据长这样:

1403715273542000000, 1.234, 2.345, 3.456, 0.123, 0.234, 0.345, 0.912
1403715273643000000, 1.245, 2.356, 3.467, 0.124, 0.235, 0.346, 0.913

为什么会有这种差异?因为EuRoC数据集是用工业相机采集的,时间精度要求更高。你想想看,视觉SLAM对时间同步的要求有多苛刻。

格式转换提醒: 如果你想把EuRoC转成TUM格式,记得把纳秒除以1e9。我写过一个脚本专门干这事,回头可以分享。

4.5 常见错误格式排查

做轨迹评估这几年,我踩过的坑真不少。下面这些是我遇到最多的:

  1. 分隔符问题:有人用逗号,有人用空格,有人用Tab。工具一般只认空格或Tab
  2. 四元数顺序:TUM格式是 qx qy qz qw,但有人写成 qw qx qy qz
  3. 时间戳单位:秒还是毫秒?纳秒还是微秒?这个搞错了,对齐全废
  4. 空行和注释:有些文件末尾有多余空行,工具会报错
  5. 数值精度:小数点后位数太少,导致位姿精度丢失

避坑指南: 我曾经花了一整天调试一个评估结果,最后发现是数据文件里混入了中文字符。嗯,从那以后我写了个格式校验脚本,跑数据前先过一遍。

4.6 格式校验小工具

我自己写了个简单的Python脚本,用来快速检查数据格式:

def check_tum_format(filepath):
    with open(filepath, 'r') as f:
        lines = f.readlines()
    
    for i, line in enumerate(lines):
        if line.startswith('#') or line.strip() == '':
            continue
        parts = line.strip().split()
        if len(parts) != 8:
            print(f"第{i+1}行:字段数不对,期望8个,实际{len(parts)}个")
            return False
        try:
            [float(p) for p in parts]
        except:
            print(f"第{i+1}行:包含非数字字符")
            return False
    print("格式检查通过!")
    return True

建议: 每次跑评估前,先用这个脚本过一遍数据。别问我为什么这么建议——问就是吃过亏。

4.7 知识体系总览

下面这张图,是我总结的数据格式核心逻辑:

轨迹数据格式核心逻辑 TUM格式 时间戳+四元数 KITTI格式 3x4变换矩阵 EuRoC格式 纳秒时间戳 共同特征:位姿数据 + 时间信息(KITTI除外) 常见问题 分隔符错误 | 四元数顺序 | 时间戳单位 | 空行注释 数值精度 | 中文字符 | 矩阵合法性

说白了,这三种格式的核心就是「位姿数据+时间信息」。KITTI虽然没时间戳,但它的矩阵结构本身也是一种规范。你只要记住一点:工具怎么读,你就怎么给。

最后说一句: 数据格式这事,看起来简单,但真出问题的时候特别隐蔽。我建议你每次换数据集,都先拿小样本跑一遍,确认格式没问题再上全量数据。省得到时候跑了一晚上,第二天发现结果全是错的。

可可精品资料库