共计 2939 个字符,预计需要花费 8 分钟才能阅读完成。
BDD100K 数据集结构解析
BDD100K 是一个大规模自动驾驶数据集,包含 10 万张图片的标注信息。原始标注采用 JSON 格式存储,每个 JSON 文件对应一个图片的标注信息,主要包括以下字段:

name: 图片文件名attributes: 图片属性(如天气、场景等)labels: 物体标注列表,每个标注包含:category: 物体类别box2d: 边界框坐标(x1, y1, x2, y2)
与 YOLO 格式相比,主要差异在于:
- 坐标表示:BDD100K 使用绝对坐标,YOLO 使用归一化后的相对坐标
- 类别表示:BDD100K 使用字符串类别名,YOLO 使用数字 ID
- 文件组织:YOLO 要求每个图片对应一个同名的 txt 标注文件
关键技术点解析
1. 坐标转换公式
YOLO 格式要求边界框中心坐标和宽高都归一化到 [0,1] 范围。转换公式如下:
x_center = (x1 + x2) / (2 * image_width)
y_center = (y1 + y2) / (2 * image_height)
width = (x2 - x1) / image_width
height = (y2 - y1) / image_height
2. 类别 ID 映射
BDD100K 有 10 个主要物体类别,我们需要建立到 YOLO 类别 ID 的映射关系:
class_map = {
'pedestrian': 0,
'rider': 1,
'car': 2,
'truck': 3,
'bus': 4,
'train': 5,
'motorcycle': 6,
'bicycle': 7,
'traffic light': 8,
'traffic sign': 9
}
Python 转换脚本实现
以下是完整的转换脚本,包含异常处理和进度显示:
import json
import os
from tqdm import tqdm
# 配置参数
json_dir = 'bdd100k/labels/'
image_dir = 'bdd100k/images/'
output_dir = 'bdd100k_yolo/'
class_map = {...} # 上面的类别映射
os.makedirs(output_dir, exist_ok=True)
for json_file in tqdm(os.listdir(json_dir)):
if not json_file.endswith('.json'):
continue
try:
with open(os.path.join(json_dir, json_file)) as f:
data = json.load(f)
# 获取图片尺寸
img_path = os.path.join(image_dir, data['name'].replace('.json', '.jpg'))
img_width, img_height = 1280, 720 # BDD100K 固定尺寸
# 准备 YOLO 格式内容
yolo_lines = []
for label in data['labels']:
if 'box2d' not in label:
continue
category = label['category']
if category not in class_map:
continue
box = label['box2d']
x1, y1, x2, y2 = box['x1'], box['y1'], box['x2'], box['y2']
# 坐标转换
x_center = (x1 + x2) / (2 * img_width)
y_center = (y1 + y2) / (2 * img_height)
width = (x2 - x1) / img_width
height = (y2 - y1) / img_height
yolo_lines.append(f"{class_map[category]} {x_center} {y_center} {width} {height}\n")
# 写入 YOLO 格式文件
output_file = os.path.join(output_dir, data['name'].replace('.json', '.txt'))
with open(output_file, 'w') as f:
f.writelines(yolo_lines)
except Exception as e:
print(f"Error processing {json_file}: {str(e)}")
转换效率优化方案
处理 10 万张图片的标注时,可以考虑以下优化:
- 多进程处理:
from multiprocessing import Pool
def process_file(json_file):
# 上面的处理逻辑
pass
if __name__ == '__main__':
json_files = [f for f in os.listdir(json_dir) if f.endswith('.json')]
with Pool(processes=8) as pool:
list(tqdm(pool.imap(process_file, json_files), total=len(json_files)))
- 内存优化:
- 避免一次性加载所有 JSON 文件
- 使用生成器逐文件处理
- 及时释放不再需要的数据
常见问题排查指南
1. 标注错误处理
- 检查边界框坐标是否在图片范围内
- 验证类别名称是否在映射表中
- 处理空标注文件
2. 格式验证方法
可以使用以下脚本验证转换后的 YOLO 格式:
def validate_yolo_format(txt_file):
with open(txt_file) as f:
for line in f:
parts = line.strip().split()
if len(parts) != 5:
return False
try:
class_id = int(parts[0])
coords = list(map(float, parts[1:]))
if not all(0 <= x <= 1 for x in coords):
return False
except ValueError:
return False
return True
数据集质量检查与训练验证
1. 质量检查
- 使用可视化工具检查标注是否正确叠加在图片上
- 统计各类别的分布情况
- 检查标注覆盖率
2. YOLOv5 训练验证
- 准备 YOLO 格式的数据集目录结构:
dataset/
├── images/
│ ├── train/
│ └── val/
└── labels/
├── train/
└── val/
- 创建 dataset.yaml 配置文件:
train: dataset/images/train/
val: dataset/images/val/
nc: 10
names: ['pedestrian', 'rider', 'car', 'truck', 'bus', 'train', 'motorcycle', 'bicycle', 'traffic light', 'traffic sign']
- 启动训练:
python train.py --img 640 --batch 16 --epochs 50 --data dataset.yaml --weights yolov5s.pt
总结
通过本文的详细指导,你应该已经掌握了将 BDD100K 数据集转换为 YOLO 格式的完整流程。这个过程虽然有些繁琐,但是理解其中的原理和实现方法后,可以轻松应对其他类似数据集的格式转换需求。在实践中如果遇到问题,可以参考我们提供的排查指南,或者查阅 YOLO 官方文档获取更多帮助。
正文完
