第五章:计算机视觉(Computer Vision)- 项目实战之目标检测实战

第二部分:目标检测实战:中国交通标志检测

第二节:中国交通标志检测数据格式转化与读取

在目标检测实战中,数据集的格式和读取方式直接决定了后续模型能否顺利训练。由于深度学习框架(如 PyTorch、TensorFlow)以及检测算法(如 YOLO、Faster R-CNN)通常要求统一的数据格式,因此需要对原始交通标志数据进行 格式转化。本节我们将详细介绍中国交通标志检测数据集的格式说明、转化流程以及数据读取方法。


1. 数据集来源与特点

常用的交通标志检测数据集包括:

  • TT100K (Tsinghua-Tencent 100K)

    • 由清华大学与腾讯联合发布,包含超过 10 万张中国交通场景图片。

    • 支持 200+ 类交通标志类别,覆盖常见的限速、禁止、警告、指示标志。

    • 原始标注为 JSON 文件,包含边界框坐标与类别标签。

  • 自建数据集(例如拍摄或采集的交通标志图片):

    • 格式可能为 VOC (XML)、COCO (JSON) 或纯文本文件,需要根据算法需求统一。


2. 常见目标检测标注格式

在转化之前,我们需要了解常见的几种标注格式:

  1. Pascal VOC 格式 (XML)

    • 每张图像对应一个 XML 文件。

    • 边界框坐标为 (xmin, ymin, xmax, ymax)

  2. COCO 格式 (JSON)

    • 所有标注集中在一个 JSON 文件中。

    • 边界框坐标为 (x, y, width, height)

  3. YOLO 格式 (TXT)

    • 每张图像对应一个 TXT 文件。

    • 每行标注格式为:

      class_id x_center y_center width height

      (所有数值均归一化到 [0, 1]


3. 数据格式转化流程

在中国交通标志检测实战中,我们选用 YOLOv8,因此需要将数据集转化为 YOLO 格式

3.1 转化步骤
  1. 下载原始数据集

    • 获取 TT100K 或其他交通标志数据集,解压缩。

  2. 解析原始标注

    • TT100K 的标注文件为 JSON,需要编写脚本读取。

  3. 统一类别文件

    • 创建 classes.txt,存放所有交通标志类别,如:

      speedlimit
      stop
      noentry
      warning
      ...
  4. 转化为 YOLO TXT 格式

    • 读取每张图像的边界框坐标,将其归一化:

      x_center = (xmin + xmax) / 2 / image_width
      y_center = (ymin + ymax) / 2 / image_height
      w = (xmax - xmin) / image_width
      h = (ymax - ymin) / image_height
    • 按照 YOLO 格式写入 TXT 文件。

  5. 目录结构整理

    • YOLO 要求的数据集目录如下:

      datasets/
      ├── images/
      │   ├── train/
      │   ├── val/
      │   └── test/
      ├── labels/
      │   ├── train/
      │   ├── val/
      │   └── test/
      └── data.yaml
  6. 编写 data.yaml

    • data.yaml 文件用于指定数据路径和类别信息,例如:

      train: ./datasets/images/train
      val: ./datasets/images/val
      test: ./datasets/images/test
      nc: 10   # 类别数量
      names: ['speedlimit', 'stop', 'noentry', 'warning', ...]

4. 数据读取与可视化

转化完成后,我们需要验证数据是否正确。

4.1 使用 Python 读取标签
import cv2
import os
img_path = "datasets/images/train/example.jpg"
label_path = "datasets/labels/train/example.txt"
# 读取图片
img = cv2.imread(img_path)
h, w, _ = img.shape
# 读取标签
with open(label_path, "r") as f:
labels = f.readlines()
for label in labels:
cls, x, y, bw, bh = map(float, label.strip().split())
# 反归一化
x1 = int((x - bw/2) * w)
y1 = int((y - bh/2) * h)
x2 = int((x + bw/2) * w)
y2 = int((y + bh/2) * h)
# 绘制边界框
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.2 可视化检查

运行后应能在图片上看到交通标志的检测框,确保:

  • 边界框位置正确。

  • 类别和 classes.txt 对应无误。

  • 数据集划分合理(训练集、验证集、测试集)。

4.3 完整代码
import json
import os
import cv2
from tqdm import tqdm
# 配置路径
json_file = "annotations.json"   # TT100K 原始 JSON 标注文件路径
img_dir = "images/"              # 原始图像文件夹
save_dir = "datasets/"           # 转换后保存的目标文件夹
# 读取 JSON 文件
with open(json_file, "r", encoding="utf-8") as f:
data = json.load(f)
# 类别映射表(TT100K 有 200+ 类,这里示例)
# 实际使用时可根据需要过滤或重命名类别
classes = list(data["types"].keys())
cls2id = {cls: i for i, cls in enumerate(classes)}
# 保存类别文件
os.makedirs(save_dir, exist_ok=True)
with open(os.path.join(save_dir, "classes.txt"), "w", encoding="utf-8") as f:
for cls in classes:
f.write(cls + "\n")
# 创建目录结构
for split in ["train", "val", "test"]:
os.makedirs(os.path.join(save_dir, "images", split), exist_ok=True)
os.makedirs(os.path.join(save_dir, "labels", split), exist_ok=True)
# 处理数据集
for split in ["train", "val", "test"]:
print(f"Processing {split} set...")
image_list = data[split]
for img_name in tqdm(image_list):
img_path = os.path.join(img_dir, img_name + ".jpg")
label_path = os.path.join(save_dir, "labels", split, img_name + ".txt")
save_img_path = os.path.join(save_dir, "images", split, img_name + ".jpg")
# 确保图片存在
if not os.path.exists(img_path):
continue
# 复制图片到新目录
if not os.path.exists(save_img_path):
os.system(f"cp {img_path} {save_img_path}")
# 读取图片尺寸
img = cv2.imread(img_path)
if img is None:
continue
h, w, _ = img.shape
# 写 YOLO 标签
with open(label_path, "w", encoding="utf-8") as f:
if img_name in data["annotations"]:
anns = data["annotations"][img_name]
for ann in anns:
cls = ann["category"]
if cls not in cls2id:
continue
# TT100K bbox 是 [xmin, ymin, xmax, ymax]
xmin, ymin, xmax, ymax = ann["bbox"]
# 转 YOLO 格式 (归一化)
x_center = (xmin + xmax) / 2 / w
y_center = (ymin + ymax) / 2 / h
bw = (xmax - xmin) / w
bh = (ymax - ymin) / h
f.write(f"{cls2id[cls]} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}\n")
print("转换完成!YOLO 数据集已生成在 datasets/ 文件夹下。")

转换结果目录结构

运行后会生成如下目录:

datasets/
├── classes.txt
├── images/
│   ├── train/
│   ├── val/
│   └── test/
└── labels/
├── train/
├── val/
└── test/

其中:

  • classes.txt 保存类别名

  • labels/*.txt 是 YOLO 格式的标签

  • images/*.jpg 是对应图片


5. 小结

  • 交通标志检测数据集常见格式包括 VOC、COCO、YOLO

  • YOLOv8 推荐采用 YOLO TXT 格式,需进行坐标归一化。

  • 数据转化后应整理为标准目录结构,并通过可视化验证标签正确性。

  • 格式转化是目标检测实战的第一步,为后续训练打下基础。

posted on 2025-10-11 08:50  ycfenxi  阅读(7)  评论(0)    收藏  举报