BDD100K数据集YOLO格式转换实战:从标注到训练的高效流程解析

1次阅读
没有评论

共计 2712 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

背景介绍

BDD100K 是伯克利大学发布的大规模自动驾驶数据集,包含 10 万张图像,涵盖多种天气和光照条件。其标注格式采用 JSON 文件存储,每个 JSON 文件对应一个图像或视频帧,包含物体类别、边界框坐标(左上角 x,y 和宽高 w,h)等信息。而 YOLO 格式则需要每个图像对应一个 txt 文件,每行存储类别 ID 和归一化后的中心坐标 (x_center, y_center) 及宽高(width, height)。

BDD100K 数据集 YOLO 格式转换实战:从标注到训练的高效流程解析

两种格式的主要差异包括:

  1. 坐标表示方式:BDD100K 使用绝对像素坐标,YOLO 需要归一化的相对坐标
  2. 文件结构:BDD100K 集中存储,YOLO 分散存储
  3. 类别标识:BDD100K 使用字符串类别名,YOLO 使用数字 ID

技术方案

1. 坐标系统转换

YOLO 格式要求将边界框坐标归一化为 0 - 1 之间的相对值,计算步骤如下:

  1. 获取图像宽度 (img_w) 和高度(img_h)
  2. 计算边界框中心点 x 坐标:x_center = (x + w/2) / img_w
  3. 计算边界框中心点 y 坐标:y_center = (y + h/2) / img_h
  4. 计算归一化宽度:width = w / img_w
  5. 计算归一化高度:height = h / img_h

2. 类别 ID 映射

BDD100K 包含 10 个主要类别,我们需要建立类别名到数字 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
}

3. 多对象处理

每个图像可能包含多个标注对象,需要将所有对象的转换结果写入同一个 txt 文件,每个对象占一行。

代码实现

以下是完整的 Python 转换脚本:

import json
import os
import cv2

# 配置路径
json_dir = 'bdd100k/labels/'
image_dir = 'bdd100k/images/'
output_dir = 'bdd100k/yolo_labels/'

# 类别映射
class_map = {# ... 同上...}

def convert_bdd_to_yolo():
    # 确保输出目录存在
    os.makedirs(output_dir, exist_ok=True)

    # 遍历所有 JSON 标注文件
    for json_file in os.listdir(json_dir):
        if not json_file.endswith('.json'):
            continue

        # 解析 JSON
        with open(os.path.join(json_dir, json_file)) as f:
            data = json.load(f)

        # 获取对应的图像文件
        image_path = os.path.join(image_dir, data['name'].replace('.json', '.jpg'))
        if not os.path.exists(image_path):
            print(f'Warning: Missing image {image_path}')
            continue

        # 获取图像尺寸
        img = cv2.imread(image_path)
        img_h, img_w = img.shape[:2]

        # 准备 YOLO 格式内容
        yolo_lines = []
        for obj in data['labels']:
            if obj['category'] not in class_map:
                continue

            # 坐标转换
            x, y, w, h = obj['box2d']['x1'], obj['box2d']['y1'], \
                         obj['box2d']['x2']-obj['box2d']['x1'], \
                         obj['box2d']['y2']-obj['box2d']['y1']

            x_center = (x + w/2) / img_w
            y_center = (y + h/2) / img_h
            width = w / img_w
            height = h / img_h

            # 格式化为 YOLO 行
            yolo_line = f"{class_map[obj['category']]} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}"
            yolo_lines.append(yolo_line)

        # 写入 YOLO 格式文件
        output_file = os.path.join(output_dir, data['name'].replace('.json', '.txt'))
        with open(output_file, 'w') as f:
            f.write('\n'.join(yolo_lines))

if __name__ == '__main__':
    convert_bdd_to_yolo()

避坑指南

  1. 文件名匹配:BDD100K 中视频帧的文件名可能与 JSON 文件名不完全对应,需要仔细检查命名规则

  2. 特殊字符处理:某些图像文件名可能包含特殊字符,建议使用 os.path 处理路径

  3. 内存优化:处理大规模数据集时,避免同时加载所有图像,应该逐个处理

  4. 多进程处理:对于超大规模数据集,可以考虑使用多进程加速

验证方法

可以使用以下 Python 代码可视化验证转换结果:

import cv2

def visualize_yolo_label(image_path, label_path):
    img = cv2.imread(image_path)
    h, w = img.shape[:2]

    with open(label_path) as f:
        for line in f:
            class_id, xc, yc, bw, bh = map(float, line.strip().split())

            # 转换回像素坐标
            x1 = int((xc - bw/2) * w)
            y1 = int((yc - bh/2) * h)
            x2 = int((xc + bw/2) * w)
            y2 = int((yc + bh/2) * h)

            # 绘制边界框
            cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)

    cv2.imshow('Validation', img)
    cv2.waitKey(0)

性能考量

  1. 图像尺寸获取是主要瓶颈,可以考虑缓存图像尺寸信息
  2. 对于超大规模数据集,JSON 解析可能成为性能瓶颈
  3. 文件 I / O 操作可以批量处理以减少系统调用

实际应用

这套转换方法不仅适用于 BDD100K 数据集,经过适当调整后可以应用于其他 JSON 格式标注的数据集转换。在实际项目中,你可能需要:

  1. 调整类别映射关系
  2. 处理不同的坐标表示方式
  3. 添加额外的属性字段

建议读者在自己的数据集上尝试这种方法,并根据具体需求进行调整。格式转换是计算机视觉项目中的常见任务,掌握这套方法可以大大提高数据准备的效率。

正文完
 0
评论(没有评论)