从KITTI原始数据到OpenPCDet可用的.pkl:一份完整的自定义数据预处理指南
从KITTI原始数据到OpenPCDet可用的.pkl:一份完整的自定义数据预处理指南
如果你正在尝试将自采集的点云数据适配到OpenPCDet框架,却卡在了数据预处理的第一步,这篇文章正是为你准备的。我们将从实际工程角度出发,解析OpenPCDet对KITTI数据的处理逻辑,并手把手教你如何改造自己的数据集。
1. 理解OpenPCDet的数据处理流程
OpenPCDet作为当前主流的3D目标检测框架,其对KITTI数据集的预处理流程可以概括为以下几个关键步骤:
- 原始数据解析:读取
.bin点云文件、图像文件和标注信息 - 数据转换:将原始标注转换为统一的坐标系表示
- 信息整合:生成包含完整样本信息的
.pkl文件 - 数据库构建:创建用于数据增强的
gt_database
关键点:整个流程的核心在于生成符合框架预期的数据结构,而非数据格式本身。这意味着只要你能提供相同结构的信息,即使数据来源不同也能顺利运行。
2. 解析KITTI数据预处理的关键文件
OpenPCDet处理KITTI数据集后会生成6个核心文件/目录,理解它们的结构和用途是适配自定义数据的基础。
2.1 信息文件(*.pkl)
这些文件存储了数据集的基本信息,主要包含以下数据结构:
{ "point_cloud": { "num_features": int, # 点云特征维度(3或4) "lidar_idx": str # 点云文件名 }, "image": { "image_idx": str, # 图像文件名 "image_shape": list # 图像尺寸[高,宽] }, "calib": { # 标定参数 "P2": np.array, # 投影矩阵 "R0_rect": np.array, # 矫正矩阵 "Tr_velo_to_cam": np.array # 雷达到相机的变换矩阵 }, "annos": { # 标注信息(测试集无此字段) "name": list[str], # 目标类别 "truncated": list[float], "occluded": list[int], # ...其他标注字段 } }2.2 数据库文件(gt_database)
这个目录存储了所有目标的点云片段,用于数据增强。每个文件命名格式为:
{点云ID}_{类别}_{目标索引}.bin例如:000000_Pedestrian_0.bin表示点云000000中的第0个行人目标。
3. 自定义数据适配实战
现在,我们来看如何将自己的点云数据转换为OpenPCDet可用的格式。
3.1 数据准备
假设你的自定义数据集结构如下:
custom_dataset/ ├── points/ # 点云文件夹(.bin或.pcd) ├── images/ # 图像文件夹(可选) ├── calibs/ # 标定参数(可选) └── labels/ # 标注文件夹3.2 创建数据转换脚本
我们需要编写一个Python脚本将自定义数据转换为KITTI格式。以下是关键代码片段:
import numpy as np import pickle from pathlib import Path def convert_custom_to_kitti(custom_root, output_dir): # 创建输出目录 output_dir = Path(output_dir) output_dir.mkdir(exist_ok=True) # 收集所有点云文件 point_files = list((Path(custom_root)/"points").glob("*.bin")) infos = [] for point_file in point_files: # 构建单个样本的信息字典 info = { "point_cloud": { "num_features": 4, # 假设使用xyzi "lidar_idx": point_file.stem }, # 添加其他信息... } infos.append(info) # 保存为pkl文件 with open(output_dir/"custom_infos_train.pkl", "wb") as f: pickle.dump(infos, f)3.3 处理标注信息
如果你的标注格式与KITTI不同,需要转换为KITTI的标注结构:
| 字段 | 类型 | 描述 |
|---|---|---|
| name | str | 目标类别 |
| truncated | float | 截断程度(0-1) |
| occluded | int | 遮挡等级(0-3) |
| alpha | float | 观察角度 |
| bbox | [float] | 2D边界框[x1,y1,x2,y2] |
| dimensions | [float] | 3D尺寸[高,宽,长] |
| location | [float] | 3D位置[x,y,z] |
| rotation_y | float | 偏航角 |
3.4 生成数据库文件
数据库文件的生成是关键步骤,它直接影响数据增强的效果。以下是核心逻辑:
def create_gt_database(infos, output_dir): db_infos = {} for info in infos: points = load_point_cloud(info["point_cloud"]["lidar_idx"]) for i, anno in enumerate(info["annos"]): # 提取目标点云 gt_points = extract_points_in_box(points, anno["gt_boxes_lidar"][i]) # 保存为单独文件 save_path = output_dir/f"{info['point_cloud']['lidar_idx']}_{anno['name'][i]}_{i}.bin" gt_points.tofile(save_path) # 添加到db_infos if anno['name'][i] not in db_infos: db_infos[anno['name'][i]] = [] db_infos[anno['name'][i]].append({ "name": anno['name'][i], "path": str(save_path), # 其他必要字段... }) # 保存db_infos with open(output_dir/"custom_dbinfos_train.pkl", "wb") as f: pickle.dump(db_infos, f)4. 常见问题与解决方案
在实际适配过程中,你可能会遇到以下典型问题:
坐标系不一致
- 问题表现:检测结果位置错乱
- 解决方案:检查
Tr_velo_to_cam矩阵是否正确转换
标注格式不匹配
- 问题表现:训练时出现维度错误
- 解决方案:确保所有标注字段与KITTI格式完全一致
点云特征维度不符
- 问题表现:模型无法正常处理输入数据
- 解决方案:在
point_cloud.num_features中正确指定特征数
提示:调试时可以先处理少量样本,使用OpenPCDet的
--cfg_file tools/cfgs/dataset_configs/kitti_dataset.yaml配置验证数据是否正确加载。
5. 性能优化技巧
当处理大规模自定义数据集时,以下技巧可以显著提升预处理效率:
- 并行处理:使用Python的
multiprocessing模块并行处理点云文件 - 内存映射:对于大型点云文件,使用
numpy.memmap避免内存爆炸 - 增量保存:分批处理数据并增量保存,避免单次处理数据量过大
# 示例:使用多进程处理 from multiprocessing import Pool def process_single_file(file_path): # 处理单个文件 pass with Pool(processes=8) as pool: pool.map(process_single_file, all_files)6. 适配其他数据集的扩展思路
虽然本文以KITTI格式为例,但同样的思路可以应用于其他格式的数据集:
- NuScenes数据集:需要处理更多传感器数据和时间序列
- Waymo数据集:需要考虑更大范围的点云和更复杂的场景
- 自定义采集数据:需要确保标定参数准确,标注规范统一
关键是要理解OpenPCDet的数据接口预期,然后编写相应的转换脚本将你的数据"翻译"成框架能理解的形式。
