ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

KITTI数据集实战:从解压到YOLO训练与SLAM融合

KITTI数据集实战:从解压到YOLO训练与SLAM融合 简介KITTI自动驾驶数据集配套脚本包面向自动驾驶、计算机视觉方向的学习者与研究者可配合数据集解析内容快速上手数据读取与基础预处理。脚本精简适合入门阶段理解KITTI的目录结构与样本组织方式。压缩包共2个文件均为Python脚本整体约5KB轻量易用不依赖复杂环境。目前已有4600余人学习下载。脚本涵盖数据加载与测试调用等基础功能既能帮助初学者避开环境配置的弯路也可作为二次开发的起点结合配套解析文章中的多模态数据组成与标注说明可在短时间内跑通KITTI数据的基础处理流程为后续物体检测、点云应用等实验打下基础。1. KITTI自动驾驶数据集.zip先认识这个包再决定怎么拆收到一个几 GB 甚至几十 GB 的 KITTI自动驾驶数据集.zip第一反应不应该是解压就完事而是想清楚你要从里面拿什么。KITTI 是自动驾驶领域被引用最多的公开数据集之一它采集自德国卡尔斯鲁厄的城乡道路包含双目图像、64 线激光点云、GPS/IMU 轨迹和 3D 标注框常被用来做目标检测、多目标跟踪、深度估计、光流和 SLAM 评估。可这个 zip 不是单一文件它内部是分场景、分模态的目录结构不同任务要的文件完全不同。这篇博客会从 zip 解压开始把目录结构、从哪几个序列拿数据、怎么把标注转成 YOLO 格式、怎么用 ORB-SLAM3YOLO 跑通以及最后怎么避免训练时常见的坑都讲清楚。适合刚入手 KITTI 的学生也适合需要二次开发标定文件的工程师。2. 解压前先看懂目录00-10 序列、标定与标签文件2.1 从 zip 解出的四层内容图像、点云、标定、标签KITTI 官方的原始数据包按序列组织每个序列如 0000、0001 到 0010就是一个独立压缩单元。你下载的 zip 解压后典型的目录布局如下2011_09_26/ ├── 0000/ │ ├── image_00/ # 左侧灰度图12Hz │ ├── image_01/ # 右侧灰度图 │ ├── image_02/ # 左侧彩色图 │ ├── image_03/ # 右侧彩色图 │ ├── oxts/ # GPS/IMU 数据10Hz │ └── velodyne_points/ # 64线激光点云10Hz ├── 0001/ └── ...注意这个结构2011_09_26是采集日期0000是序列编号。每个序列内的图像是 12Hz点云和 GPS/IMU 是 10Hz时间戳由各自的.timestamps文件记录。很多初学者直接把image_02当视频源用却忽略了点云和图像在时间上并不完全对齐后续做数据融合时会出问题。如果你是做目标检测真正要关注的是label_02目录——注意这个目录不一定在原始 zip 里它通常在单独的“label”标注压缩包中。这就是为什么有人解压完原始数据后找不到标签需要额外下载data_object_label_2.zip。zip 的名字带着“自动驾驶数据集”但没细分下载时看清单文件确认自己拿的是 raw data、labeled data 还是 calibration data。2.2 持续时间、里程与“00 序列 bag 文件”之间的关系在 SLAM 和融合定位方向大家最常提到的是 00 序列。00 序列总长约 4650 帧实际采集时间大概 7 分半钟覆盖了城市街道、环岛、建筑群和一段近距离的高架桥道路。它的轨迹闭合性较好适合做里程计漂移评估所以 ORB-SLAM3、VINS、LIO-SAM 的文档里几乎都拿 00 序列做演示。但 ROS 系统不直接读 zip 里的原始目录它需要把图像和点云按时间戳封装成 bag 文件。热词里提到的kitti 00序列bag文件就是这么来的为了在 ROS 里跑 ORB-SLAM3YOLO你先得把 00 序列的图像和点云转成一个 bag。这个转换用的是kitti2bag工具后面第 3 章会专门讲命令。序列帧数approx主要道路环境常见用途004650城市高架SLAM 里程计评估011100高速高速场景检测024660乡村城市长距离跟踪03800城市快速验证052760住宅区多传感器融合标定061100住宅区小规模测试071100城市道路低纹理环境测试084070乡村城市通用训练补充2.3 标定文件里 P_rect、R_rect 与 Tr_velo_to_cam解压后的calib目录如在2011_09_26下的calib_velo_to_cam.txt、calib_cam_to_cam.txt放的是传感器外参和内参。做 KITTI 标注转 YOLO 时你必须理解两个矩阵P_rect3x4 的投影矩阵把相机坐标系下的 3D 点投影到图像像素坐标。P_rect_02对应左侧彩色相机image_02。R_rect3x3 的旋转矩阵用于将点云坐标系下的点先做相机坐标系的旋转校正。Tr_velo_to_cam3x4 外参矩阵把 Velodyne 激光雷达坐标系变换到校正前的相机坐标系。整体变换链是激光雷达点 P_lidar - 乘 Tr_velo_to_cam 得到 P_cam - 乘 R_rect 得到 P_rect_cam - 乘 P_rect 得到齐次像素坐标 (u, v)代码里经常有人把Tr_velo_to_cam和R_rect的顺序弄反导致点云投影到图像上整体偏移。正确顺序是先外参、后旋转校正、最后投影。另外calib_cam_to_cam.txt中还有 S_xx、K_xx、D_xx 等相机内参和畸变系数做去畸变或相机标定时会用到。3. 下载校验与解压把服务器上的 KITTI 转成本地能训练的数据集3.1 从下载链接到 zip 包断点续传与 MD5 校验KITTI 官网的下载链接通常是直链但部分镜像走 HTTP。用wget下载时别用默认参数加上断点续传和超时重试是基本操作wget -c -t 0 --timeout30 --waitretry5 \ -O data_object_label_2.zip \ https://s3.eu-central-1.amazonaws.com/avg-kitti/data_object_label_2.zip参数说明-c表示断点续传下载到一半断了可以直接继续-t 0是无限重试--timeout30是单次连接超时时间--waitretry5是失败后等待 5 秒再重试。下载完成后要校验 MD5KITTI 官网每个压缩包都给了 MD5 值比如data_object_label_2.zip的 MD5 需要你在页面核对后写入脚本。本地校验命令md5sum data_object_label_2.zip3.2 解压后的盘面规划SSD 放标签、HDD 放原始数据解压命令本身不复杂unzip data_object_label_2.zip -d ./kitti_label unzip 2011_09_26_calib.zip -d ./kitti_raw但解压完的目录相当占空间。原始序列的velodyne_points是二进制点云一个序列就几 GB00 序列解压后约 5GB 左右彩色图像再加一倍。我的习惯是SSD 上只放label_02、calib和image_02把velodyne_points留在 HDD——因为做 2D 检测训练时根本读不到点云做 SLAM 时又希望点云顺序读取HDD 的连续读取带宽足够。这样既省 SSD 空间又避免把大量二进制小文件拷来拷去。3.3 用 kitti2bag 把 zip 里的文件转成 rosbag如果你要用 ROS 跑 ORB-SLAM3 或需要把数据流式重放最省事的方式是用kitti2bag。先安装依赖pip install kitti2bag pykitti然后对 00 序列执行kitti2bag -t 2011_09_26 -r 00 raw_synced 00.bag说明-t 2011_09_26是指定采集日期目录名-r 00是指定序列号raw_synced表示使用已同步的原始数据目录最后00.bag是输出 bag 文件路径。如果你的目录结构是2011_09_26/2011_09_26_drive_0000_sync这种带_sync后缀的kitti2bag 会自动识别。生成后可以快速检查 bag 内容rosbag info 00.bagrosbag info会输出时长、话题列表、消息数量和频率。正常情况下你会看到/kitti/camera_color_left/image_raw、/kitti/velo/pointcloud、/kitti/oxts/gps/fix、/kitti/oxts/imu这些话题。如果话题里没有点云说明 velodyne 目录路径不对或者序列号选错。bag 生成后播放频率默认是原始速度你在rosbag play时可以用-r 0.5放慢速度方便观察 YOLO 检测框和 SLAM 地图更新的匹配情况。4. 从标注到训练KITTI 转 YOLO 格式再接入 ORB-SLAM34.1 理解 KITTI 的 3D 标注框再转成 YOLO 的 2D 框KITTI 标签格式每行代表一个 3D 物体字段依次为类别 截断 遮挡 观察角度 bbox_left bbox_top bbox_right bbox_bottom height width length x y z rotation_y其中bbox_left bbox_top bbox_right bbox_bottom是 2D 检测框单位为像素x y z是物体中心在相机坐标系下的坐标rotation_y是物体绕 y 轴的朝向。做 YOLO 训练时我们只需要类别和bbox四个像素坐标然后归一化到 0~1。有个常见误解KITTI 的bbox是从 3D 框投影得到的 2D 框而不是直接用 3D 框的包围盒。这导致如果你从 point cloud 里取 3D 框再投影可能和标签里的 2D 框不一致。所以转 YOLO 时直接读 KITTI 标签里的 2D bbox 即可不需要做任何投影计算。4.2 一个可复用的 KITTI 转 YOLO 转换脚本下面这段 Python 脚本把 KITTI 标签文件转成 YOLO 格式的 txt 文件同时做类别过滤和框边界裁剪import os KITTI_CLASSES [Car, Pedestrian, Cyclist, Van, Truck, Person_sitting] IMG_WIDTH 1242 IMG_HEIGHT 375 def kitti_to_yolo(kitti_line, img_w, img_h): parts kitti_line.strip().split() if len(parts) 15: return None cls_name parts[0] if cls_name not in KITTI_CLASSES: return None left, top, right, bottom map(float, parts[4:8]) left max(0, min(left, img_w - 1)) right max(0, min(right, img_w - 1)) top max(0, min(top, img_h - 1)) bottom max(0, min(bottom, img_h - 1)) if right left or bottom top: return None x_center (left right) / 2.0 / img_w y_center (top bottom) / 2.0 / img_h box_w (right - left) / img_w box_h (bottom - top) / img_h cls_id KITTI_CLASSES.index(cls_name) return f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}\n def convert_label_dir(label_dir, output_dir, img_w1242, img_h375): os.makedirs(output_dir, exist_okTrue) for fname in sorted(os.listdir(label_dir)): if not fname.endswith(.txt): continue in_path os.path.join(label_dir, fname) out_path os.path.join(output_dir, fname.replace(.txt, .txt)) with open(in_path, r) as fin, open(out_path, w) as fout: for line in fin: yolo_line kitti_to_yolo(line, img_w, img_h) if yolo_line: fout.write(yolo_line) if __name__ __main__: convert_label_dir(kitti_label/training/label_2, yolo_labels)转换后的格式是类别ID x_center y_center width height所有数值归一化在 0~1 之间。注意脚本做了两件事一是过滤掉DontCare类别二是对越界的框做了裁剪。前者是因为 DontCare 没有明确的目标语义YOLO 训练时把它当背景反而会导致误检后者是因为 KITTI 图像固定 1242x375但少数标注框会有一点越界裁剪后避免负数归一化产生 NaN。另外类别顺序KITTI_CLASSES要和你的 YOLO 配置文件里的names保持一致否则训练时类别 ID 错位。4.3 用 ORB-SLAM3YOLO 在 KITTI 数据集上跑通把 YOLO 检测结果接入 ORB-SLAM3核心思路是用 YOLO 的 2D 框过滤特征点只保留落在动态物体上的特征点并删除从而避免动态物体干扰位姿估计。网络热词里提到orb-slam3yolo如何在kitti数据集上跑通这里给出一条最简单的路径。第一步编译 ORB-SLAM3 并确保能正常跑 KITTI 00 序列cd ORB_SLAM3 ./build.sh ./Examples/Stereo/stereo_kitti \ Vocabulary/ORBvoc.txt \ Examples/Stereo/KITTI00-02.yaml \ /path/to/2011_09_26/2011_09_26_drive_0000_sync第二步把 YOLO 封装成一个 ROS 节点订阅/kitti/camera_color_left/image_raw输出检测框 topic。这里的关键参数是置信度阈值和 IoU 阈值KITTI 图像中目标尺寸偏大但数量少建议conf_thres0.4、iou_thres0.5。置信度太低会把路牌当行人太高会漏掉远处的骑车人。第三步在 ORB-SLAM3 的 Tracking 线程里加入检测框过滤对当前帧提取的 ORB 特征点判断其像素坐标是否落在任何 YOLO 框内若是则将该特征点标记为 dynamic 并从匹配池剔除。这个过程不需要修改 ORB-SLAM3 的核心优化结构只需在Track()中插入一段过滤函数。测试时把 YOLO 框可视化到图像上同时打印剔除特征点数量如果每帧剔除数超过总特征点的 30%说明动态物体占比过高需要调低 YOLO 阈值或扩大过滤框。你要注意一个容易踩的坑KITTI 图像是 12Hz 而 YOLO 推理在普通 GPU 上可能只能跑 10~30ms勉强跟得上但在 CPU 上很可能掉帧。常见做法是先用rosbag play -r 0.5降速或者用 YOLO-tiny 变体而不是完整 YOLOv5s。实时性优先时把输入分辨率从 1242x375 resize 到 640x384检测精度损失对动态物体过滤来说基本可接受。5. 进阶用排行榜与验证集划分做实验管理避开三个常见坑5.1 KITTI 排行榜的返回策略提交、回归与测试集不可见KITTI 官网排行榜目前对目标检测、跟踪、深度估计、光流都提供了在线评测。你把模型在训练集上训练好把预测结果按照题目要求打包上传官网在你提交后返回测试集指标例如 mAP、AP 等。注意测试集标签不公开也不能用训练集或验证集数据去“过拟合测试集”。一个实用的做法是在本地把训练集内部再拆出一个验证集用验证集做早停和超参选择排行榜提交只做最终报告。这样既保证了模型在本地可复现又不至于每次调参都要等官网排队。5.2 训练/验证/测试集的合理划分与数据增强KITTI 的官方划分是 7481 张训练图像其中标签齐全的是 7481 张官方又把它分成 train3712和 val3769两个集合。如果直接拿这 7481 张做 5 折交叉验证每次训练都要重新转换标注费时费力。我的做法是把 7481 张按序列文件编号的奇偶性分开奇数做 train偶数做 val。这样同一个视频序列的连续帧不会同时出现在训练和验证里避免时间相关性的数据泄露。数据增强方面YOLO 训练时建议只做轻微色彩抖动和随机翻转不要做强几何变换如旋转或裁剪。因为 KITTI 是车载前视视角物体朝向和尺度分布和一般物体检测数据集不同过度增强反而会让模型学到不真实的视角特征。增强比例建议控制在 0.2 以下即每张图最多有 20% 的概率触发色彩抖动。5.3 三个常见的坑时间戳不同步、标注遮挡截断、目录权限第一时间戳不同步。KITTI 的相机是 12Hz、点云是 10Hz如果你用 zip 里的原始目录转换成视频流直接按帧索引去对齐图像和点云会错位。官方在sync目录中已经按时间对齐过但如果你下载的是raw未同步版本必须用时间戳插值。常见做法是取每个点云时刻之前最近的图像帧作为匹配图像而不是按帧号硬对齐。第二标注遮挡和截断。KITTI 标签中的遮挡字段取值 0~3 表示遮挡程度截断字段取值 0~1 表示目标被图像边界截断的比例。训练时如果你把截断大于 0.5 的框强行转成 YOLO 框目标可能只有半个车身YOLO 的 anchor 匹配会非常不稳定。建议在转 YOLO 时直接过滤掉截断大于 0.3 或遮挡大于 2 的标注只保留清晰目标。第三目录权限和软链接。把数据集放到多卡服务器的共享存储上时NFS 挂载的文件经常出现Permission denied影响 PyTorch DataLoader 读取。你可以在解压后先执行find /path/to/kitti -type d -exec chmod 755 {} \;并确认图片文件权限为 644。读取时用os.listdir检查前 10 个文件是否可打开避免训练中途才暴露权限问题。最后提一个验证技巧把 YOLO 模型的训练曲线mAP0.5和 KITTI 排行榜的 AP 对照如果本地验证集 mAP 很高但排行榜 AP 低优先检查标注转换时的类别映射和框尺寸归一化是否有偏差而不是盲目调模型结构。排行榜分数对框的偏移非常敏感检测框中心偏移 5 个像素在 1242x375 的图像上可能就导致 AP 掉 2 个百分点。本文还有配套的精品资源点击获取
返回列表