作为算法工程师,我们不仅仅需要知道算法的精度、误差如何,更需要的是知道为什么误差比较大,性能不太好,我该从哪个方面来做优化,提升算法性能?
因此,我调研了目前常见的性能评估工具,并分析他们的局限性,最终认为应该定制一个自己的Vo评估工具。
1. 公开评估工具原理概述
1.1 KITTI Benchmark (CVPR 2012)
评估指标:
-
t_error (平均平移误差百分比):
t_error = (1/N) Σ ||trans(T_gt[i]^(-1) · T_est[i])||_2 / length_i × 100% -
r_error (平均旋转误差):
r_error = (1/N) Σ angle(T_gt[i]^(-1) · T_est[i]) (deg/m)
核心特点:
- 使用 SE(3) 刚体对齐(无尺度因子),因为KITTI的GT来自GPS/IMU/激光,有真实尺度
- 按序列长度分段计算(100m, 200m, ..., 800m),反映不同距离下的漂移
- 不提供逐帧误差曲线,只有统计量
1.2 TUM RGB-D Benchmark (IROS 2012)
评估指标:
- ATE (Absolute Trajectory Error):全局Sim(3)对齐后的RMSE
- RPE (Relative Pose Error):固定时间/帧间隔的相对位姿误差
核心特点:
- 单目VO使用 Sim(3) Umeyama对齐(7DoF:旋转+平移+尺度)
- 时间戳对齐:位置线性插值 + 旋转SLERP
- 提供逐帧误差,支持时序可视化
1.3 EVO工具
功能模块:
| 命令 | 功能 | 局限 |
|---|---|---|
evo_ape |
计算ATE(绝对位姿误差) | 仅输出误差,无内部状态 |
evo_rpe |
计算RPE(相对位姿误差) | 同上 |
evo_traj |
轨迹可视化 | 静态展示,无诊断信息 |
evo_res |
多结果对比 | 汇总统计量,无时序关联 |
核心特点:
- 支持TUM/KITTI/EuRoC/ROS bag多种格式
- 算法正确性对标论文标准实现
- 输出灵活(LaTeX图表、Excel表格等)
- 各命令独立运行,无法在一个视图中同时展示误差+轨迹+内部状态
2. 为什么公开工具使用起来不够称手?
2.1 核心矛盾:评估 vs 诊断
| 维度 | 公开工具(EVO/KITTI/TUM) | 我想要的工具 |
|---|---|---|
| 目标用户 | 算法研究者/论文作者 | 算法工程师/开发者 |
| 核心诉求 | 得到一组可对比的指标 | 定位问题根因并优化 |
| 输入数据 | 轨迹文件 + GT文件 | 轨迹 + GT + 内部状态日志 |
| 输出形式 | 统计量 + 静态图 | 交互式诊断报告 |
| 工作流程 | 跑完→看数字→写结论 | 跑完→发现问题→定位原因→优化→验证 |
关键认知转变:
- 公开工具回答的是:"这个算法好不好?"(性能评估)
- 我想要的工具回答的是:"为什么这里不好?怎么改进?"(诊断优化)
2.2 具体局限分析
局限1:无法关联内部状态
VO系统运行时会输出丰富的内部状态,这些是诊断的关键线索:
| 时间戳 | num_inliers | 重投影误差 | 尺度估计 | 关键帧标记 | |
|---|---|---|---|---|---|
| 12.3s | 180 | 1.2px | 1.05 | ✓ | 正常 |
| 12.4s | 45 ⚠️ | 3.8px ⚠️ | 1.12 | ✗ | 特征骤减 |
| 12.5s | 38 ⚠️ | 4.2px ⚠️ | 1.18 | ✗ | 持续恶化 |
| 12.6s | 165 | 1.5px | 1.06 | ✓ | 恢复 |
EVO无法做到:
- 将
num_inliers与RPE误差画在同一时间轴上对比 - 查看尺度突变时是否伴随关键帧重置
- 分析重投影误差与旋转误差的相关性
自建工具可以做到:
python
# 叠加诊断图:RPE + inliers + scale + ATE 四行共享x轴
Row 1: RPE Translation Error (m) ← 蓝色曲线
Row 2: num_inliers ← 绿色柱状
Row 3: Scale Factor (local) ← 橙色曲线
Row 4: ATE Error (m) ← 红色曲线
看到RPE飙升 → 同时刻inliers骤降 → 根因定位:该区间纹理匮乏导致特征匹配失败
局限2:分离的命令无法整体视图
EVO的使用体验:
bash
# 需要分三次运行,三个独立窗口
evo_ape tum gt.txt est.txt --align sim3 --plot # 窗口1:ATE
evo_rpe tum gt.txt est.txt --delta 10 --plot # 窗口2:RPE
evo_traj tum gt.txt est.txt --plot # 窗口3:轨迹
# 无法在一张图中对比
自建工具的体验:
bash
python -m evaluate --gt gt.txt --est est.txt -o report/
# 自动生成 report/dashboard.html:
# ┌─────────────────────────────────────────┐
# │ 3D轨迹对比(GT黑/EST红/对齐后EST蓝) │
# ├─────────────────────────────────────────┤
# │ 2D俯视图 + 关键帧位置标记 │
# ├─────────────────────────────────────────┤
# │ position x/y/z 时序曲线对比 │
# ├─────────────────────────────────────────┤
# │ rotation r/p/y 时序曲线对比 │
# ├─────────────────────────────────────────┤
# │ ATE曲线 + 统计参考线 │
# ├─────────────────────────────────────────┤
# │ RPE曲线(双轴:平移+旋转) │
# ├─────────────────────────────────────────┤
# │ 尺度漂移曲线(累积+局部) │
# └─────────────────────────────────────────┘
局限3:缺乏尺度漂移分析能力
单目VO的特殊痛点 :
单目VO存在时变尺度漂移,全局Sim(3)对齐只能给出一个"平均最优"尺度,无法反映尺度变化过程。
真实尺度变化:s=1.0 → s=1.05 → s=0.98 → s=1.02 (波动)
↓
Umeyama全局对齐:s=1.01 (单一值)
↓
结果:轨迹两端被系统性放大,形成"U型"ATE曲线(对齐伪影)
EVO无法提供:
- 逐帧尺度估计曲线
- 局部尺度漂移分析(滑动窗口)
- 尺度突变点定位
自建工具提供:
python
# 累积尺度:反映长期趋势
s_cum[i] = ||p_est[i] - p_est[0]|| / ||p_gt[i] - p_gt[0]||
# 局部尺度:反映瞬时质量,消除累积效应
s_local[i] = ||p_est[i+w] - p_est[i]|| / ||p_gt[i+w] - p_gt[i]||
局限4:缺乏分段诊断能力
全局对齐的欺骗性 :
全局Umeyama对齐会"掩盖"局部问题。一条轨迹可能有前半段好、后半段差,但全局对齐后RMSE只是中等水平。
EVO的做法:
- 整条轨迹做一次对齐 → 输出一个RMSE
- 无法区分"全局一致性差" vs "局部跟踪差"
自建工具的分段ATE:
python
segment_size = 100 # 每100帧一段独立对齐
for seg in segments:
s, R, t = umeyama(seg_est, seg_gt) # 每段独立求最优尺度
ate_seg = rmse(aligned - seg_gt)
# 结果解读:
# - 各段RMSE都小 → 全局一致性差(可能回环没闭合)
# - 某段RMSE特别大 → 该区间确实有问题(需深入诊断)
局限5:自动化与定制化需求
实际开发流程的自动化需求:
bash
# 每次改参数后需要:
1. 跑VO生成轨迹
2. 跑evo_ape → 记录ATE
3. 跑evo_rpe → 记录RPE
4. 手动截图保存
5. 汇总到Excel对比
自建工具的自动化:
bash
# 一键完成:评估 → 可视化 → 报告 → 对比
python -m evaluate \
--gt gt.txt \
--est "exp_*/trajectory_tum.txt" \ # 批量评估多组实验
--state sf_slam.txt \
-o report/
# 自动生成:
# - summary.json:所有指标汇总(可用于参数网格搜索)
# - dashboard.pdf:完整诊断视图
# - comparison_table.csv:多实验对比
定制化需求示例:
- 只关心特定时间段(如排除初始化阶段)
- 自定义误差阈值高亮
- 添加业务特定的指标(如关键帧密度、重置次数)
- 与CI/CD集成,PR自动跑评估并评论结果
局限6:数据格式与场景适配
EVO的格式要求:
- 必须使用TUM/KITTI/EuRoC标准格式
- 时间戳必须精确对齐
- 不支持内部状态日志
实际项目中的数据:
- 自研VO的输出格式可能不标准
- 内部状态日志(slam.txt)包含关键诊断信息
- 多段轨迹(trajectory_tum.txt, trajectory_tum_1.txt...)需要自动合并
- 时间戳可能有偏移或不同采样率
自建工具可以内置:
- 格式转换和校验
- 时间戳自动对齐(插值/最近邻)
- 多段轨迹自动发现与合并
- 内部状态解析与关联
3. 决策建议
什么时候用EVO?
✅ 适合场景:
- 快速验证算法正确性
- 论文投稿需要标准对比指标
- 与公开数据集(KITTI/TUM/EuRoC)的结果对比
- 不需要深入诊断,只要一个数字
什么时候自建工具?
✅ 适合场景:
- 算法工程化开发阶段(需要持续优化)
- 单目VO(需要尺度漂移分析)
- 复杂场景(需要结合内部状态诊断)
- 批量实验对比(参数搜索/消融实验)
- 团队协作(需要统一报告格式)
混合策略(推荐)
┌─────────────────────────────────────────────────────────────┐
│ 阶段1:算法原型验证 │
│ → 使用EVO快速得到ATE/RPE,确认算法基本正确 │
└───────────────────────┬─────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 阶段2:工程优化阶段 │
│ → 使用自建工具进行深度诊断,结合内部日志定位问题 │
└───────────────────────┬─────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 阶段3:论文/报告撰写 │
│ → 使用EVO生成标准对比表格(审稿人熟悉) │
│ → 使用自建工具生成特色诊断图(展示工程深度) │
└─────────────────────────────────────────────────────────────┘
4. 参考文献
- Geiger et al., "Are we ready for Autonomous Driving? The KITTI Vision Benchmark Suite", CVPR 2012
- Sturm et al., "A Benchmark for the Evaluation of RGB-D SLAM Systems", IROS 2012
- Grupp, "evo: Python package for the evaluation of odometry and SLAM", 2017 (https://github.com/MichaelGrupp/evo)
- Zhang & Scaramuzza, "A Tutorial on Quantitative Trajectory Evaluation for Visual(-Inertial) Odometry", IROS 2018
- Umeyama, "Least-squares estimation of transformation parameters between two point patterns", IEEE TPAMI 1991
5. 总结
| 核心差异 | 公开工具(EVO) | 自建工具 |
|---|---|---|
| 定位 | 性能评估(回答"好不好") | 诊断优化(回答"为什么+怎么办") |
| 数据 | 轨迹+GT | 轨迹+GT+内部状态 |
| 视图 | 分离的命令 | 一体化dashboard |
| 尺度分析 | ❌ 不支持 | ✅ 累积+局部尺度 |
| 分段诊断 | ❌ 不支持 | ✅ 分段ATE |
| 内部状态叠加 | ❌ 不支持 | ✅ RPE+inliers+scale同轴 |
| 自动化 | 手动分步 | 一键批量 |
最终结论:
- EVO是"尺子":用来量长短、比好坏
- 自建工具是"听诊器":用来查病因、开药方
在算法工程化开发阶段,我们需要的是听诊器,而不仅仅是尺子。
特此记录,欢迎交流。