news 2026/5/7 21:59:13

BDD100K数据集标签转换实战:从JSON到YOLO格式的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
BDD100K数据集标签转换实战:从JSON到YOLO格式的完整指南

1. BDD100K数据集与YOLO格式简介

当你第一次接触BDD100K数据集时,可能会被它的JSON标签格式搞得一头雾水。这个由伯克利大学发布的自动驾驶数据集包含10万个视频片段,覆盖了各种天气、光照和道路场景,是训练目标检测模型的绝佳资源。但问题来了——YOLOv5/YOLOv8需要的是TXT格式的标签,每个文件对应一张图片,记录着归一化的目标位置和类别。

我刚开始用这个数据集时,花了一整天研究如何转换格式。后来发现,其实核心就是三步:解析JSON里的box2d坐标、按需筛选类别、将绝对坐标转为相对坐标。举个例子,JSON中一个"car"的坐标可能是{"x1": 320, "y1": 240, "x2": 480, "y2": 360},而YOLO需要的则是"0 0.5 0.5 0.25 0.25"这样的格式(假设类别car对应数字0)。

2. 环境准备与数据目录结构

在开始转换前,建议按这个结构组织你的文件夹:

bdd100k/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── det_annotations/ # 原始JSON标签 │ ├── train/ │ └── val/ └── yolo_labels/ # 转换后的TXT标签 ├── train/ └── val/

需要安装的Python包其实很简单:

pip install json numpy tqdm

我建议用tqdm加个进度条,特别是处理几万张图片时,看着进度条慢慢走完会有种莫名的治愈感。曾经有一次我没用进度条,程序跑了半小时我都不知道是否卡死了,最后忍不住强制终止,结果发现已经处理完了...

3. JSON标签解析实战

BDD100K的JSON结构比COCO复杂些,关键是要找到"frames"下的"objects"数组。每个对象包含:

  • category:类别名称(如"car")
  • box2d:包含x1,y1,x2,y2的边界框
  • attributes:可能有交通灯颜色等额外属性

这里有个坑:不同版本的BDD100K标签结构略有差异。有次我拿到的版本里,"frames"变成了"labels",害我debug了好久。建议先用这个代码检查结构:

import json with open("sample.json") as f: data = json.load(f) print(json.dumps(data, indent=2)[:500]) # 打印前500字符

4. 类别筛选与映射策略

BDD100K有13个基础类别,但你可能只需要其中几个。我整理了这个对照表:

BDD原始类别保留标记YOLO类别ID
car0
pedestrian-
traffic light1
.........

实现时建议用字典管理类别映射:

CLASS_MAP = { "car": 0, "traffic light": 1, "traffic sign": 2 }

处理交通灯时要特别注意,颜色信息藏在attributes里:

if obj["category"] == "traffic light": color = obj["attributes"]["trafficLightColor"] class_name = f"tl_{color}" # 如tl_red

5. 坐标归一化关键细节

这是最容易出错的部分!YOLO要求的是中心点坐标和宽高,且必须是相对于图像尺寸的比例值。计算公式如下:

def normalize_bbox(x1, y1, x2, y2, img_w=1280, img_h=720): x_center = (x1 + x2) / 2 / img_w y_center = (y1 + y2) / 2 / img_h width = (x2 - x1) / img_w height = (y2 - y1) / img_h return x_center, y_center, width, height

注意BDD100K默认分辨率是1280x720,但有些图片可能不同。安全起见,可以检查JSON中的"resolution"字段。我曾经因为忽略这个,导致小目标检测完全失效——所有框都偏移了20%!

6. 完整代码实现与优化

结合上述要点,这是优化后的转换代码:

import json import os from tqdm import tqdm class BDD2YOLO: def __init__(self): self.class_map = { "car": 0, "traffic light": 1, "traffic sign": 2, "person": 3 } def convert(self, json_path, output_dir): os.makedirs(output_dir, exist_ok=True) with open(json_path) as f: data = json.load(f) filename = data["name"] lines = [] for frame in data["frames"]: for obj in frame["objects"]: category = obj["category"] if category not in self.class_map: continue # 处理交通灯颜色 if category == "traffic light": color = obj["attributes"].get("trafficLightColor", "none") category = f"tl_{color}" # 坐标归一化 box = obj["box2d"] xc, yc, w, h = self.normalize_bbox( box["x1"], box["y1"], box["x2"], box["y2"] ) lines.append( f"{self.class_map[category]} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}\n" ) # 保存结果 if lines: with open(f"{output_dir}/{filename}.txt", "w") as f: f.writelines(lines) @staticmethod def normalize_bbox(x1, y1, x2, y2, img_w=1280, img_h=720): xc = (x1 + x2) / 2 / img_w yc = (y1 + y2) / 2 / img_h w = (x2 - x1) / img_w h = (y2 - y1) / img_h return xc, yc, w, h # 批量处理 converter = BDD2YOLO() json_dir = "bdd100k/labels/det_annotations/train" output_dir = "bdd100k/labels/yolo_labels/train" for filename in tqdm(os.listdir(json_dir)): converter.convert( f"{json_dir}/{filename}", output_dir )

这个版本比原始代码增加了错误处理、进度显示和更清晰的代码结构。用类封装也让后续维护更方便。

7. 验证与调试技巧

转换完成后,强烈建议做这些检查:

  1. 空文件检查:有些图片可能没有目标,确保对应的TXT文件为空或不存在
  2. 坐标范围验证:所有坐标值应在[0,1]范围内
  3. 可视化验证:用OpenCV画框检查是否对齐

这里有个可视化脚本片段:

import cv2 def visualize(img_path, label_path, class_names): img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path) as f: for line in f: cls_id, xc, yc, bw, bh = map(float, line.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.putText(img, class_names[int(cls_id)], (x1,y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 1) cv2.imshow("Preview", img) cv2.waitKey(0)

8. 性能优化与批量处理

当处理10万级数据时,我有几个提速心得:

  1. 多进程处理:Python的multiprocessing模块能大幅提升速度
from multiprocessing import Pool def process_file(filename): converter.convert(f"{json_dir}/{filename}", output_dir) with Pool(8) as p: # 8个进程 list(tqdm(p.imap(process_file, os.listdir(json_dir)), total=len(os.listdir(json_dir))))
  1. 缓存机制:如果中断后重新开始,可以跳过已处理的文件
  2. SSD存储:机械硬盘处理小文件速度会慢很多

最后提醒:转换完成后,记得在YOLO的配置文件中正确设置类别数和类别名称。比如在data.yaml中:

names: ["car", "traffic light", "traffic sign", "person"]
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/2 11:25:02

锚框实战:用Python从零构建目标检测锚框系统

锚框实战:用Python从零构建目标检测锚框系统 在计算机视觉领域,目标检测一直是核心挑战之一。想象一下,当你需要让计算机不仅识别图像中有什么物体,还要精确标出它们的位置时,传统分类网络就力不从心了。这就是锚框技…

作者头像 李华
网站建设 2026/4/28 20:14:14

YOLOv10官版镜像命令行预测,三步搞定超省心

YOLOv10官版镜像命令行预测,三步搞定超省心 你是否经历过这样的场景:刚下载好目标检测模型,打开终端准备跑个预测,结果卡在环境配置上——CUDA版本不匹配、PyTorch安装报错、ultralytics库版本冲突……折腾两小时,连一…

作者头像 李华
网站建设 2026/4/26 16:25:13

Streamlit+mT5开源镜像免配置教程:中文文本增强工具快速搭建指南

StreamlitmT5开源镜像免配置教程:中文文本增强工具快速搭建指南 1. 这不是另一个“调API”工具,而是一个真正开箱即用的本地中文改写助手 你有没有遇到过这些场景? 写完一段产品描述,想换个说法发在不同平台,又怕语…

作者头像 李华
网站建设 2026/4/28 5:15:14

零基础玩转TranslateGemma:企业级翻译系统一键安装教程

零基础玩转TranslateGemma:企业级翻译系统一键安装教程 你是否遇到过这些场景: 翻译一份英文技术文档,反复粘贴到网页版工具里,等加载、防限流、格式错乱;开发中需要把一段英文需求快速转成 Python 代码逻辑&#xf…

作者头像 李华
网站建设 2026/5/7 14:29:23

造相-Z-Image显存优化揭秘:如何避免OOM错误

造相-Z-Image显存优化揭秘:如何避免OOM错误 在本地部署文生图模型时,你是否经历过这样的崩溃瞬间:刚输入提示词、点击生成,控制台突然弹出一长串红色报错——CUDA out of memory,紧接着进程被强制终止?更令…

作者头像 李华