
简介面向自动驾驶研究人员与计算机视觉学习者的KITTI数据集配套脚本包用于解决原始数据获取门槛高、格式解析繁琐的问题。包内共2个文件均为Python脚本涵盖下载链接校验与常见解析逻辑可在本地直接运行帮助按需获取图像、激光雷达点云及标注信息。压缩包仅5KB轻量简洁体积小、易上手适合搭配完整KITTI数据集使用。已有4636人学习下载适合正在入门自动驾驶感知、需要快速搭建数据准备流程的开发者。脚本虽精简但提供了清晰的调用结构与扩展入口使用者可基于自身需求调整路径与下载范围节省手工检索整理时间。配合KITTI的传感器说明与标注规范能帮助理解多模态数据组织方式为后续目标检测、跟踪或SLAM实验提供数据支撑加速算法迭代。1. KITTI自动驾驶数据集.zip解压前先分清raw data和odometry很多人把KITTI自动驾驶数据集zip下载回来后第一反应是双击解压然后直接去找image_2文件夹结果视觉SLAM跑出来的轨迹乱成麻。原因往往不是算法不行而是你手里的压缩包对应哪个基准都不清楚。KITTI自动驾驶数据集按用途分成raw data、odometry benchmark、object detection benchmark等几类压缩包结构差异很大。这篇围绕zip下载、解压、目录整理、数据解析和格式转换展开覆盖常见做法用命令行解压避免乱码、用calib.txt对齐传感器坐标、把标注转成YOLO格式、把00序列变成bag文件并用ORB-SLAM3做一次可复现的验证。适合要做SLAM、目标检测或数据预处理的工程师也适合刚拿到数据集还不知道从哪下手的同学。2. KITTI数据集zip的解压命令与目录整理2.1 用unzip或7z解压别用图形界面双击KITTI数据集单个zip很容易超过20GB图形界面双击解压有两个问题一是看不到解压进度二是中断后无法精准续传。命令行下我一般先列出压缩包内容确认目录unzip -l KITTI_dataset.zip | less 7z l KITTI_dataset.zipunzip -l只读不解压能快速看到顶层目录是dataset/还是2011_09_26/这决定了后面的路径脚本怎么写。确认无误后解压mkdir -p /data/kitti cd /data/kitti unzip -o /path/KITTI_dataset.zip -d /data/kitti 21 | tail -20参数含义-o覆盖已有文件断点重跑不会反复问你是否覆盖-d指定解压目标目录避免压缩包内多级目录把文件散落一地21 | tail -20只保留最后20行输出几十万个小文件刷屏时会严重影响排查速度。如果机器上装了7-Zip我会优先用7z x多线程解压面对大量小文件更快7z x /path/KITTI_dataset.zip -o/data/kitti -y注意-o后面不能有空格这是7z和unzip最容易混淆的地方。场景推荐命令关键参数只查看zip内容unzip -l 或 7z l不加-d完整解压unzip -o -d指定目标目录大文件快速解压7z x -o 路径-y跳过确认校验压缩包unzip -t-t表示测试CRC提示解压前用df -h确认目标分区剩余空间至少为zip体积的1.2倍。KITTI的zip解压后往往比压缩包大30%以上磁盘写满会导致velodyne里的.bin文件截断这种损坏用肉眼很难发现。2.2 Windows下压缩的zip在Linux解压出现乱码KITTI官方数据文件几乎全英文但很多网盘或同学二次打包时会带中文说明。Windows默认用GBK编码文件名Linux下直接unzip会看到乱码目录。解决办法是让unzip按GBK解码unzip -O GBK KITTI_dataset.zip -d /data/kitti如果系统里的unzip不支持-O参数先装p7zip再解压7z x KITTI_dataset.zip -o/data/kitti -yGBK问题只影响文件名显示不影响文件二进制内容。真正要小心的是解压后文件权限unzip默认保留压缩包内权限位KITTI数据集里的可执行脚本可能没有执行权限后续跑评估工具时记得补chmod x。2.3 整理odometry序列让ORB-SLAM3直接读取从KITTI官网odometry benchmark下载的zip一般解压后是sequences目录里面有00到21共22个序列。但很多整合包会把04这类短序列单独放或者把raw data的2011_09_26_drive_0002_sync目录直接塞进来。我一般会统一成ORB-SLAM3能识别的布局mkdir -p /data/kitti/dataset/sequences for seq in 00 01 02 03 04 05 06 07 08 09 10; do mv /data/kitti/source/${seq} /data/kitti/dataset/sequences/${seq} done mkdir -p /data/kitti/dataset/poses cp /data/kitti/source/poses/*.txt /data/kitti/dataset/poses/这段脚本假设source里是解压出来的原始序列目录。sequences/xx下面必须有image_0、image_1、velodyne和calib.txtORB-SLAM3的stereo_kitti示例会直接读取这些名字。不要试图手动改程序里的文件路径先把目录名和文件名对齐标准布局后面复现别人的参数配置时能省掉大量调试时间。提示raw data的2011_09_26目录和odometry的sequences目录不能混用。raw data每段只有几十秒适合做传感器标定SLAM回归测试用odometry的00-10序列才是常见做法。3. 读懂KITTI数据集结构图像、点云、标定与时间戳3.1 KITTI odometry每个序列里有什么KITTI自动驾驶数据集odometry benchmark的每个序列比如sequences/00目录结构固定为sequences/00/ ├── calib.txt ├── times.txt ├── image_0/ (灰度左相机约1242x375) ├── image_1/ (灰度右相机) ├── image_2/ (彩色左相机) ├── image_3/ (彩色右相机) └── velodyne/ (HDL-64E激光雷达点云每帧一个.bin)注意poses/不在序列目录里而在odometry的poses总目录下每行12个数字对应3x4位姿矩阵。用ORB-SLAM3评估轨迹时这个文件不是必须的但可以用来算ATE。文件/目录内容读取方式calib.txt相机投影矩阵P0-P3、激光雷达到相机外参按行解析浮点数times.txt每帧时间戳单位秒文本按行读取image_0/1/2/3灰度或彩色图OpenCV imreadvelodyne/*.bin4维floatx,y,z,reflectionnumpy.fromfileposes/xx.txt每行12个float的位姿矩阵reshape(3,4)KITTI图像尺寸在不同序列基本是1242x375但不要硬编码到所有处理脚本里读取图像后再取宽高更可靠。image_0是已经做过畸变矫正和立体校正的灰度图所以SLAM里不需要再做undistort而raw data的图像则需要先校正才能用。3.2 用Python解析calib.txt弄清坐标系变换calib.txt里每行长这样具体数值随序列变化P0: 7.215377e02 0.000000e00 6.095593e02 ... P1: 7.215377e02 0.000000e00 6.095593e02 ... P2: 7.215377e02 0.000000e00 6.095593e02 ... P3: 7.215377e02 0.000000e00 ... Tr: 4.276802e-01 -9.999672e-01 ...解析时不能按固定列数读因为矩阵名和数值数量对应关系容易弄错。常见做法是按行拆分用键名区分矩阵类型import numpy as np def read_kitti_calib(calib_path): calib {} with open(calib_path, r) as f: for line in f: line line.strip() if not line: continue tokens line.split() key tokens[0].rstrip(:) values np.array(tokens[1:], dtypenp.float64) if key.startswith(P): calib[key] values.reshape(3, 4) elif key Tr: calib[Tr] values.reshape(3, 4) return calib逻辑说明tokens[0]是P2:这种带冒号的键用rstrip(:)去掉冒号后当字典键。P0-P3是3x4投影矩阵作用是把相机坐标系下的3D点投影到对应图像像素坐标Tr实际是Tr_velo_to_cam官方简化写成Tr作用是把激光雷达坐标系下的点变换到左相机坐标系。所以把velodyne点云投影到图像平面的完整做法是pts_velo load_velodyne_bin(velodyne/000000.bin)[:, :3] pts_cam (calib[Tr] np.c_[pts_velo, np.ones(len(pts_velo))].T).T pts_cam pts_cam[:, :3] pts_img (calib[P2] np.c_[pts_cam, np.ones(len(pts_cam))].T).T pts_img pts_img[:, :2] / pts_img[:, 2:3]这里的参数细节值得多说一句np.c_在最后一列补1把3D点转成齐次坐标。P2本身是3x4左乘后得到齐次像素坐标最后再除以第三维得到像素u,v。点云里可能有点在相机后方投影后坐标是乱的后续做图像投影时先过滤z 0的点。3.3 读取velodyne裸二进制别被点云格式绕晕velodyne下的.bin不是PLY或PCD是原始float数组每个点占16字节依次是x, y, z, reflection。读取时用numpy最直接def load_velodyne_bin(bin_path): pc np.fromfile(bin_path, dtypenp.float32) pc pc.reshape(-1, 4) return pc一个容易踩的坑是np.fromfile读空文件不会报错而是返回空数组后面reshape(-1,4)会直接抛ValueError。所以解压后我建议抽查几个bin文件文件大小一致且能被16整除时再批量处理。KITTI原始点云通常单帧有几万个点如果读取后点数明显偏少优先怀疑zip解压不完整。时间戳文件times.txt每行一个浮点数表示该帧相对序列起始时间单位秒。raw data的timestamps.txt则是完整日期字符串。两者不要混用。ORB-SLAM3的KITTI示例并不读取时间戳而是按顺序逐帧处理如果要把结果作为rosbag重放就需要用times.txt给每帧生成ROS时间戳否则RVIZ里所有点云会堆在同一时刻。4. 把KITTI数据集转成能直接用的格式YOLO标注、rosbag与ORB-SLAM34.1 KITTI标注格式转YOLO的完整脚本KITTI目标检测benchmark的标签在label_2目录每一行格式是Car 0.00 0.00 590.00 170.00 716.00 200.00 1.89 1.55 4.06 -9.20 1.70 25.51 -1.75 2.35 2.57含义依次是类别、截断、遮挡、2D框四个值left, top, right, bottom、3D尺寸、3D位置、旋转yaw。YOLO训练只需要类别和2D框所以转换脚本核心是提取第0和第5-8个字段再归一化到图像宽高import os def convert_kitti_labels(label_dir, out_dir, img_w1242, img_h375): os.makedirs(out_dir, exist_okTrue) for name in sorted(os.listdir(label_dir)): if not name.endswith(.txt): continue src os.path.join(label_dir, name) dst os.path.join(out_dir, os.path.splitext(name)[0] .txt) with open(src, r) as f_in, open(dst, w) as f_out: for line in f_in: parts line.strip().split() if len(parts) 15: continue cls parts[0] x1, y1, x2, y2 float(parts[4]), float(parts[5]), float(parts[6]), float(parts[7]) box_w (x2 - x1) / img_w box_h (y2 - y1) / img_h x_center (x1 x2) / 2.0 / img_w y_center (y1 y2) / 2.0 / img_h f_out.write(f{cls} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}\n)逻辑说明KITTI标签在2D框之前还夹着截断和遮挡两个数字所以坐标从第5个字段开始。YOLO要求类别ID而不是字符串上面脚本保留类别名属于偷懒写法正经训练时建议先建立classes.txt映射把Car、Pedestrian等映射成整数。如果要用目标检测对比算法KITTI官方排行榜本身就是一个统一的评测口径同一套测试集上比mAP能少踩很多结果对不齐的坑。注意KITTI图像存在零填充导致右侧有黑色边框不同序列宽度不完全一致。如果从图像文件读取宽高而不是写死1242转换结果对raw data同样适用。4.2 把00序列导出成bag文件要在ROS里重放KITTI 00序列常见做法是借助KITTI数据集导出工具mkdir -p /data/rosbag python kitti2bag -t 00 -s 00 -d /data/kitti/dataset mv 00.bag /data/rosbag/参数说明-t是序列号00-s是起始时间段对odometry数据两者保持一致。-d指向KITTI根目录。执行前要确认机器上的ROS环境已生效否则rosbag相关组件不可用。导出完成后用rosbag info检查话题数量rosbag info 00.bag你会看到至少包含灰度相机、彩色相机、velodyne点云和IMU/GPS数据的话题。注意KITTI数据原始帧率不同相机约10Hzvelodyne约10HzIMU约100Hz。重放时用--rate0.5放慢看每帧细节用--rate5加速回归。如果只是给目标检测吃图只订阅图像话题就够了如果做多传感器融合务必确认时间戳对齐字段是times.txt里的浮点秒不是ROS启动后的墙钟。4.3 ORB-SLAM3在KITTI数据集上跑通的最小配置直接跑ORB-SLAM3的KITTI stereo示例命令格式为cd ORB_SLAM3 ./Examples/Stereo/stereo_kitti \ Vocabulary/ORBvoc.txt \ Examples/Stereo/KITTI00-02.yaml \ /data/kitti/dataset/sequences/00三个参数分别是词典文件、相机配置yaml和序列根目录。KITTI00-02.yaml里的关键参数必须和KITTI标定文件对齐常见要核对这几个参数作用常见错误Camera.fx / Camera.fy相机焦距从calib.txt的P2矩阵取值Camera.cx / Camera.cy主点坐标没对齐P2的第0、1、5、6列Camera.bf基线乘焦距直接抄别人的值导致深度漂移Camera.width/height图像宽高与KITTI 1242x375不一致时越界崩如果要把YOLO接到ORB-SLAM3上我不建议改SLAM内部代码而是开两个进程一个进程跑stereo_kitti输出轨迹另一个进程订阅图像话题跑YOLO检测框再用时间戳或帧号关联。这样最省事也能避免YOLO前向推理的时延拖垮SLAM线程。检测结果挂到图像上后用RVIZ能同时看到地图点和障碍物框这一步就是很多语义SLAM演示的基础版本。5. KITTI数据集zip完整性与点云抽查解压后先做这两件事5.1 解压前先测完整解压后再验hashzip在网盘里传过一手坏一个扇区就可能让某个velodyne bin文件缺字节。解压前先测一遍unzip -t KITTI_dataset.zip | tail -5 7z t KITTI_dataset.zip-t是测试模式逐文件解压到内存比对CRC不落盘。几十GB的zip测试可能要20分钟以上但它能避免你后续训练到第3万步才发现某帧点云是坏的。解压后更可靠的做法是比对文件数unzip -l KITTI_dataset.zip | tail -1 find /data/kitti/dataset/sequences/00/velodyne -name *.bin | wc -l如果两者数值不一致直接用7z重新解压对应文件。5.2 抽查点云坐标范围排除坐标错乱单独一个bin文件读出来是float数组但坐标对不对得用统计量看。写一个快速检查脚本import numpy as np def check_bin(path): pc np.fromfile(path, dtypenp.float32).reshape(-1, 4) if pc.shape[0] 0: raise ValueError(empty point cloud) pts pc[:, :3] print(points:, pts.shape[0]) print(x range:, pts[:, 0].min(), pts[:, 0].max()) print(y range:, pts[:, 1].min(), pts[:, 1].max()) print(z range:, pts[:, 2].min(), pts[:, 2].max())正常KITTI Velodyne点云x/y大致在几十米范围内地面点z接近0车辆和杆柱的z有正有负。如果看到x全是0或者z全大于100检查是不是把calib.txt的行顺序搞错了或解压时文件被截断。多点抽查时用连续的三个bin文件分别检查如果点数骤减或某维值跳变应该回到zip校验环节。另一个技巧是把第3章的read_kitti_calib和这个检查脚本合在一起对同一帧点云做投影生成一张标注好边界框的可视化图。这样不仅能验证点云还能验证标定等于把整个数据链路打通。输出全是OK之后这批KITTI数据集zip才算真正可用了。本文还有配套的精品资源点击获取