1. 为什么你需要关注KITTI到YOLOv5的格式转换
如果你正在入门自动驾驶或者计算机视觉,KITTI数据集大概率是你绕不开的一个名字。它太经典了,包含了丰富的城市场景、各种天气和光照条件下的图像,以及精确的3D和2D标注。但当你兴冲冲地下载好几十个G的数据,准备用当下最火的YOLOv5模型来训练一个自己的目标检测器时,一盆冷水可能就浇下来了:直接运行训练脚本,大概率会报错,或者训练出来的模型根本不认识任何物体。
问题出在哪?核心就在于数据格式不匹配。KITTI有自己一套独特的标注格式,而YOLOv5期望的是另一种完全不同的格式。这就好比你把一本英文说明书交给一个只懂中文的工人,他当然没法干活。这个“翻译”的过程,就是格式转换,也是从数据到模型最关键、也最容易卡住新手的一步。
我刚开始做这个转换的时候,也踩了不少坑。比如,KITTI里把“卡车”、“厢式货车”分得很细,但YOLOv5训练时我们可能只想用一个“汽车”大类来概括;再比如,坐标从绝对的像素值转换到相对的中心点坐标,这个计算要是搞错了,框就全飘到图像外面去了。更头疼的是,数据集里偶尔还会有些“特殊”的标注文件,用常规的转换脚本一跑就报错,让人摸不着头脑。
所以,这篇文章的目的,就是把我趟过的路、踩过的坑,整理成一个清晰、可复现的实战指南。我会手把手带你理解两种格式的差异,用代码演示每一步转换,并分享处理那些“捣蛋”文件的技巧。目标很简单:让你能独立、顺利地把原始的KITTI数据,变成YOLOv5能“吃”得下的训练集,真正跑起来你自己的自动驾驶感知模型。
2. 理解核心差异:KITTI格式 vs YOLOv5格式
想要正确转换,首先得搞清楚双方到底在用什么“语言”交流。我们拿一个具体的KITTI标签文件(比如 000000.txt)来开刀,看看里面到底写了啥。
2.1 拆解KITTI的“一行诗”
KITTI的标注通常是一个文本文件,每行代表一个物体。我们看一个典型例子:
Pedestrian 0.00 0 -0.20 712.40 143.00 810.73 307.92 1.89 0.48 1.20 1.84 1.47 8.41 0.01
这一长串数字看起来有点吓人,但其实它有固定的顺序。我们把它拆开看:
- 第1列
Pedestrian:物体类别。KITTI原始类别有好多,比如 Car, Van, Truck, Pedestrian, Person_sitting, Cyclist, Tram, Misc, DontCare 等。 - 第2列
0.00:截断程度。表示物体在图像边界被截断的比例(0-1),这个在YOLO格式里通常不用。 - 第3列
0:遮挡等级。表示物体被遮挡的程度(0=完全可见,1=部分遮挡,2=大部分遮挡,3=未知)。这个信息很有用,但基础YOLO格式也不直接支持。 - 第4列
-0.20:观察角度。物体的朝向角(弧度),对于3D感知很重要,但2D检测的YOLO暂时用不上。 - 第5-8列
712.40 143.00 810.73 307.92:这是我们转换的核心! 它们分别代表2D边界框的左上角x坐标、左上角y坐标、右下角x坐标、右下角y坐标。注意,这是绝对的像素坐标。 - 第9列及之后:主要是物体的3D尺寸(高、宽、长)、3D位置(x, y, z)和旋转角等,用于3D检测,我们做2D目标检测可以先忽略。
所以,对于YOLOv5训练,我们最需要关注的就是类别名和那四个框的坐标。
2.2 YOLOv5想要什么样的“食物”
YOLOv5(以及YOLO系列大部分版本)需要的标签格式则简洁得多。同样对应一个物体,它是一行这样的数据:
2 0.6217 0.6081 0.0801 0.4432
这五个数字分别代表:
- 第1个
2:类别索引。这是一个整数,从0开始。它对应一个类别列表,比如[‘Car’, ‘Cyclist’, ‘Pedestrian’],那么0就是Car,1是Cyclist,2就是Pedestrian。这里最容易出错:你代码里定义的类别顺序,必须和模型训练时配置文件里的顺序完全一致,否则训练出来标签全是乱的。 - 第2个
0.6217:边界框中心点的 x坐标 / 图像宽度。这是一个归一化后的相对坐标,范围在0到1之间。 - 第3个
0.6081:边界框中心点的 y坐标 / 图像高度。 - 第4个
0.0801:边界框的 宽度 / 图像宽度。 - 第5个
0.4432:边界框的 高度 / 图像高度。
看到关键区别了吗?KITTI给的是绝对的像素坐标(左上角、右下角),而YOLO要的是归一化的相对坐标(中心点、宽高)。这个转换需要一点简单的数学计算。另外,KITTI的类别是字符串,YOLO要的是整数索引,这就需要我们建立一个映射关系。
3. 实战第一步:数据准备与目录搭建
在开始写代码转换之前,把文件和目录整理好,能避免后面很多路径错误。我习惯用一个清晰的目录结构,这里分享我的做法。
首先,从KITTI官网下载数据。如果觉得官网下载慢,也可以找一些国内镜像或整理好的数据集包。通常我们需要的是“2D Object Detection”任务的data_object_image_2.zip(图像)和data_object_label_2.zip(标签)。解压后,你会得到 training/image_2(图片)和 training/label_2(标签)这两个文件夹。
由于完整KITTI数据集有七千多张图片,对于初次实验或快速验证来说太大了。我建议先取一个子集,比如前500张(000000.png 到 000499.png),等流程跑通后再用全量数据。我们可以用简单的Python脚本来复制这些文件。
接下来,搭建一个类似VOC格式的目录,这样很多现成的工具和脚本更容易适配。在你的项目根目录下,创建如下结构:
VOCdevkit/
└── VOC2007/
├── Annotations/ # 存放中间转换的XML文件(可选步骤)
├── JPEGImages/ # 存放所有的.png图片文件
├── YOLOLabels/ # 存放最终给YOLO的.txt标签文件
└── predefined_classes.txt # 记录我们定义的类别列表
JPEGImages:把选中的KITTI图片(.png格式)全部放进来。虽然叫JPEGImages,但放png完全没问题。YOLOLabels:先空着,我们转换后的YOLO格式标签会放在这里。predefined_classes.txt:这是一个纯文本文件,里面按行写下你想要的类别,例如:
Car
Cyclist
Pedestrian
千万记住这个顺序,它决定了类别索引号(Car=0, Cyclist=1, Pedestrian=2)。这个文件后面会被我们的转换脚本读取。
4. 核心转换流程:三步走脚本详解
理解了原理,搭建好了目录,现在就是最关键的转换环节了。我会把转换过程拆解成三个清晰的Python脚本,每个脚本负责一个特定任务,并解释其中容易踩坑的地方。
4.1 脚本一:类别清洗与合并
KITTI的原始类别对于精细研究是好事,但对于我们训练一个泛化能力强的检测器,有时需要合并。比如,把 Truck、Van、Tram 都合并到 Car 这个大类里,把 Person_sitting 合并到 Pedestrian。同时,像 DontCare(忽略区域)和 Misc(难以分类的物体)这类标签,在训练时我们是不需要的,可以直接过滤掉。
下面这个脚本 modify_annotations_txt.py 就是干这个的。它会读取原始KITTI标签,进行合并和过滤,并输出清洗后的标签到原文件(或新文件)。注意:运行前最好备份原始标签!
# modify_annotations_txt.py
import glob
import os
#

90

被折叠的 条评论
为什么被折叠?



