从KITTI Raw Data到LIO-SAM适配包:定制化数据集制作全流程解析
1. KITTI数据集与LIO-SAM适配的核心挑战
当你第一次拿到KITTI Raw Data时,可能会觉得这就像是一箱未经分类的乐高积木——所有零件都在,但直接用来拼装特定模型(比如LIO-SAM)却总差那么几个关键连接件。我去年在部署自动驾驶小车时就遇到过这个典型问题:官网下载的标准数据集在ROS中转换成bag包后,LIO-SAM死活报错点云格式不匹配。
根本原因在于LIO-SAM对点云数据有特殊要求。普通激光SLAM算法只需要XYZI(坐标+强度)四维数据,但LIO-SAM这个"挑食者"还要求每个点必须携带ring(激光线束编号)和time(相对时间戳)信息,也就是完整的XYZIRT六维数据。这就好比普通电视机接上RF信号就能看,但4K HDR电视必须要有HDMI 2.1接口的特定信号源。
KITTI原始数据中的velodyne_points文件夹虽然包含.bin格式的点云数据,但默认只存储XYZI信息。要提取ring和time这两个隐藏属性,必须下载带"extract"和"sync"后缀的原始数据包。这就像你要做满汉全席,普通超市买的食材不够用,得去专业食材市场采购。
2. 数据下载与预处理实战
2.1 精准获取所需数据文件
在KITTI官网的Raw Data页面,你会看到类似"2011_09_30_drive_0033_extract"和"2011_09_30_drive_0033_sync"这样的文件组合。前者包含原始传感器数据,后者是经过时间同步的版本。我强烈建议下载sync版本,否则后续要自己处理时间对齐这个"魔鬼细节"。
实际操作中我发现,不同日期的数据集存在微妙差异。比如2011_09_26的数据缺少某些校准文件,而2011_09_30的数据最完整。这里分享我的选择策略:
- 优先选择包含完整校准文件的日期(如2011_09_30)
- 单次实验尽量使用同一天采集的多个drive序列
- 高速公路场景(如2011_10_03)的点云密度与城市道路不同,需要区别处理
2.2 校准文件的关键作用
下载包里那些看似不起眼的txt校准文件,其实是数据转换的"密码本"。特别是calib_velo_to_cam.txt和calib_cam_to_cam.txt这两个文件,它们记录了激光雷达与相机之间的坐标变换关系。我在初期就犯过错误——直接用默认参数转换,结果点云和图像完全对不上。
正确的做法是先用Python脚本验证校准参数:
import numpy as np # 读取velodyne到相机的变换矩阵 with open('calib_velo_to_cam.txt') as f: lines = f.readlines() R = np.array(lines[1].strip().split(' ')[1:], dtype=np.float32).reshape(3,3) T = np.array(lines[2].strip().split(' ')[1:], dtype=np.float32) print(f"旋转矩阵:\n{R}\n平移向量:{T}")3. 数据转换核心技术解析
3.1 深度改造kitti2bag脚本
官方提供的kitti2bag.py脚本需要动三个关键手术才能产出LIO-SAM可用的bag包:
- 时间戳重映射:原始脚本使用文件修改时间作为ROS消息戳,这会导致后续时间同步问题。需要改为从timestamps.txt读取精确时间:
with open('velodyne_points/timestamps.txt') as ts_file: timestamps = [datetime.strptime(line.strip(), '%Y-%m-%d %H:%M:%S.%f') for line in ts_file]- ring信息注入:Velodyne HDL-64E激光雷达的64线束编号需要根据点云垂直角度计算:
# 计算每个点的线束编号 vertical_angle = np.arctan2(z, np.sqrt(x**2 + y**2)) * 180 / np.pi ring = int((vertical_angle + 24.8) / (49.6/63)) # HDL-64E参数- 相对时间戳生成:每个扫描周期内点的相对时间需要线性插值:
points_time = np.linspace(0, scan_duration, num_points)3.2 转换过程的质量控制
运行转换脚本时,我习惯用--visualize参数实时查看点云:
python3 kitti2bag.py -t 2011_09_30 -r 0033 raw_synced --visualize健康的数据转换应该满足三个指标:
- 点云强度值分布呈现双峰特征(地面和物体分离)
- 相邻帧匹配度高于60%(使用ICP算法验证)
- 轨迹漂移率每小时小于2%(可用EVO工具评估)
4. 实战验证与调优技巧
4.1 回环检测的特殊处理
KITTI的05序列(高速公路场景)是检验回环检测的"试金石"。但原始GPS数据在隧道区域会出现跳变,需要特别处理:
- 在转换时保留原始GPS话题:
gps_msg = NavSatFix() gps_msg.header.stamp = timestamp gps_msg.latitude = oxts[0] gps_msg.longitude = oxts[1] bag.write('/gps/fix', gps_msg, timestamp)- 在LIO-SAM配置中启用混合定位:
useGPS: true gpsCovThreshold: 2.04.2 轨迹评估的黄金标准
使用EVO工具评估时,我发现两个容易踩的坑:
- 时间对齐:必须用--align参数进行时间轴匹配
- 尺度统一:KITTI数据建议添加--correct_scale参数
典型评估命令:
evo_ape kitti ground_truth.txt lio_sam_result.txt -r full --plot --plot_mode xz --align --correct_scale优质轨迹的APE指标应该满足:
- 城市场景:<1% (中值误差)
- 高速场景:<2%
- 回环闭合误差:<0.5m
5. 效率优化与批量处理
当需要处理多个序列时,可以用GNU parallel实现并行转换:
parallel -j 4 python3 kitti2bag.py -t 2011_09_30 -r {} raw_synced ::: 0033 0034 0035对于超长序列(如超过5000帧),建议分割处理:
- 按每1000帧生成子bag包
- 用rosbag index生成索引文件
- 最后用rosbag merge进行无损合并
存储优化方面,采用LZ4压缩可以减小70%体积:
rosbag compress --lz4 output.bag