TT100K 数据集

Tsinghua-Tencent 100K (TT100K) 是一个大规模交通标志基准数据集,由 100,000 张腾讯街景全景图创建而成。该数据集专为真实场景下的交通标志检测与分类而设计,为研究人员和开发人员构建稳健的交通标志识别系统提供了综合资源。

该数据集包含 100,000 张图像,涵盖 221 个标注类别中的超过 30,000 个交通标志实例。原始论文针对监督学习应用了每类 100 个实例的阈值,得出了常用的 45 类子集;然而,提供的 Ultralytics 数据集配置文件保留了所有 221 个标注类别,其中许多类别非常稀疏。这些图像捕捉了光照、天气条件、观察角度和距离方面的巨大变化,使其成为训练需要在多样化真实世界场景中可靠运行的模型的理想选择。

该数据集对于以下用途特别有价值:

  • 自动驾驶系统
  • 高级驾驶辅助系统 (ADAS)
  • 交通监控应用
  • 城市规划与交通分析
  • 真实世界条件下的计算机视觉研究

主要特性

TT100K 数据集提供了几个关键优势:

  • 规模:100,000 张高分辨率图像 (2048×2048 像素)
  • 多样性:涵盖中国交通标志的 221 个交通标志类别
  • 真实世界条件:天气、光照和观察角度的巨大变化
  • 丰富的标注:每个标志都包含类别标签、边界框 (BBox) 和像素掩码
  • 全面覆盖:包括禁令标志、警告标志、指示标志和辅助标志
  • 训练/测试集划分:预先定义好的划分,用于一致性评估

数据集结构

TT100K 数据集被分为三个子集:

  1. 训练集: 用于训练模型以检测和分类不同类型交通标志的主要交通场景图像集合。
  2. 验证集: 在模型开发过程中用于监控性能和调整超参数的子集。
  3. 测试集: 一组预留的图像集合,用于评估最终模型在真实场景中检测和分类交通标志的能力。

TT100K 数据集包含 221 个交通标志类别,组织为几个主要组:

限速标志 (pl, pm)**

  1. pl_:禁止限速标志 (pl5, pl10, pl20, pl30, pl40, pl50, pl60, pl70, pl80, pl100, pl120)
  2. pm_:最低限速标志 (pm5, pm10, pm20, pm30, pm40, pm50, pm55)

禁令标志 (p, pn, pr_)**

  1. p1-p28:常规禁令标志(禁止通行、禁止停车、禁止停放等)
  2. pn/pne:禁止通行和禁止停车标志
  3. pr:各种限制标志 (pr10, pr20, pr30, pr40, pr50 等)

警告标志 (w_)

  1. w1-w66:针对各种道路危险、路况和情况的警告标志
  2. 包括人行横道、急转弯、路滑、动物、施工等。

限高/限宽标志 (ph, pb)**

  1. ph_:限高标志 (ph2, ph2.5, ph3, ph3.5, ph4, ph4.5, ph5 等)
  2. pb_:限宽标志

指示标志 (i, il, io, ip)**

  1. i1-i15:常规指示标志
  2. il_:限速信息标志 (il60, il80, il100, il110)
  3. io:其他指示标志
  4. ip:信息板

数据集 YAML

YAML (Yet Another Markup Language) 文件用于定义数据集配置。它包含有关数据集路径、类别和其他相关信息。对于 TT100K 数据集,TT100K.yaml 文件包含自动下载和转换功能。

ultralytics/cfg/datasets/TT100K.yaml
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license

# Tsinghua-Tencent 100K (TT100K) dataset https://cg.cs.tsinghua.edu.cn/traffic-sign/ by Tsinghua University
# Documentation: https://cg.cs.tsinghua.edu.cn/traffic-sign/tutorial.html
# Paper: Traffic-Sign Detection and Classification in the Wild (CVPR 2016)
# License: CC BY-NC 2.0 license for non-commercial use only
# Example usage: yolo train data=TT100K.yaml
# parent
# ├── ultralytics
# └── datasets
#     └── TT100K ← downloads here (~18 GB)

# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: TT100K # dataset root dir
train: images/train # train images (relative to 'path') 6105 images
val: images/val # val images (relative to 'path') 7641 images (original 'other' split)
test: images/test # test images (relative to 'path') 3071 images

# Classes (221 traffic sign categories, 45 with sufficient training instances)
names:
  0: pl5
  1: pl10
  2: pl15
  3: pl20
  4: pl25
  5: pl30
  6: pl40
  7: pl50
  8: pl60
  9: pl70
  10: pl80
  11: pl90
  12: pl100
  13: pl110
  14: pl120
  15: pm5
  16: pm10
  17: pm13
  18: pm15
  19: pm20
  20: pm25
  21: pm30
  22: pm35
  23: pm40
  24: pm46
  25: pm50
  26: pm55
  27: pm8
  28: pn
  29: pne
  30: ph4
  31: ph4.5
  32: ph5
  33: ps
  34: pg
  35: ph1.5
  36: ph2
  37: ph2.1
  38: ph2.2
  39: ph2.4
  40: ph2.5
  41: ph2.8
  42: ph2.9
  43: ph3
  44: ph3.2
  45: ph3.5
  46: ph3.8
  47: ph4.2
  48: ph4.3
  49: ph4.8
  50: ph5.3
  51: ph5.5
  52: pb
  53: pr10
  54: pr100
  55: pr20
  56: pr30
  57: pr40
  58: pr45
  59: pr50
  60: pr60
  61: pr70
  62: pr80
  63: pr90
  64: p1
  65: p2
  66: p3
  67: p4
  68: p5
  69: p6
  70: p7
  71: p8
  72: p9
  73: p10
  74: p11
  75: p12
  76: p13
  77: p14
  78: p15
  79: p16
  80: p17
  81: p18
  82: p19
  83: p20
  84: p21
  85: p22
  86: p23
  87: p24
  88: p25
  89: p26
  90: p27
  91: p28
  92: pa8
  93: pa10
  94: pa12
  95: pa13
  96: pa14
  97: pb5
  98: pc
  99: pg
  100: ph1
  101: ph1.3
  102: ph1.5
  103: ph2
  104: ph3
  105: ph4
  106: ph5
  107: pi
  108: pl0
  109: pl4
  110: pl5
  111: pl8
  112: pl10
  113: pl15
  114: pl20
  115: pl25
  116: pl30
  117: pl35
  118: pl40
  119: pl50
  120: pl60
  121: pl65
  122: pl70
  123: pl80
  124: pl90
  125: pl100
  126: pl110
  127: pl120
  128: pm2
  129: pm8
  130: pm10
  131: pm13
  132: pm15
  133: pm20
  134: pm25
  135: pm30
  136: pm35
  137: pm40
  138: pm46
  139: pm50
  140: pm55
  141: pn
  142: pne
  143: po
  144: pr10
  145: pr100
  146: pr20
  147: pr30
  148: pr40
  149: pr45
  150: pr50
  151: pr60
  152: pr70
  153: pr80
  154: ps
  155: w1
  156: w2
  157: w3
  158: w5
  159: w8
  160: w10
  161: w12
  162: w13
  163: w16
  164: w18
  165: w20
  166: w21
  167: w22
  168: w24
  169: w28
  170: w30
  171: w31
  172: w32
  173: w34
  174: w35
  175: w37
  176: w38
  177: w41
  178: w42
  179: w43
  180: w44
  181: w45
  182: w46
  183: w47
  184: w48
  185: w49
  186: w50
  187: w51
  188: w52
  189: w53
  190: w54
  191: w55
  192: w56
  193: w57
  194: w58
  195: w59
  196: w60
  197: w62
  198: w63
  199: w66
  200: i1
  201: i2
  202: i3
  203: i4
  204: i5
  205: i6
  206: i7
  207: i8
  208: i9
  209: i10
  210: i11
  211: i12
  212: i13
  213: i14
  214: i15
  215: il60
  216: il80
  217: il100
  218: il110
  219: io
  220: ip

# Download script/URL (optional) ---------------------------------------------------------------------------------------
download: |
  import json
  import shutil
  from pathlib import Path

  from PIL import Image

  from ultralytics.utils import TQDM
  from ultralytics.utils.downloads import download

  def tt100k2yolo(dir):
      """Convert TT100K annotations to YOLO format with images/{split} and labels/{split} structure."""
      data_dir = dir / "data"
      anno_file = data_dir / "annotations.json"

      print("Loading annotations...")
      with open(anno_file, encoding="utf-8") as f:
          data = json.load(f)

      # Build class name to index mapping from yaml
      names = yaml["names"]
      class_to_idx = {v: k for k, v in names.items()}

      # Create directories
      for split in ["train", "val", "test"]:
          (dir / "images" / split).mkdir(parents=True, exist_ok=True)
          (dir / "labels" / split).mkdir(parents=True, exist_ok=True)

      print("Converting annotations to YOLO format...")
      skipped = 0
      for img_id, img_data in TQDM(data["imgs"].items(), desc="Processing"):
          img_path_str = img_data["path"]
          if "train" in img_path_str:
              split = "train"
          elif "test" in img_path_str:
              split = "test"
          else:
              split = "val"

          # Source and destination paths
          src_img = data_dir / img_path_str
          if not src_img.exists():
              continue

          dst_img = dir / "images" / split / src_img.name

          # Get image dimensions
          try:
              with Image.open(src_img) as img:
                  img_width, img_height = img.size
          except Exception as e:
              print(f"Error reading {src_img}: {e}")
              continue

          # Copy image to destination
          shutil.copy2(src_img, dst_img)

          # Convert annotations
          label_file = dir / "labels" / split / f"{src_img.stem}.txt"
          lines = []

          for obj in img_data.get("objects", []):
              category = obj["category"]
              if category not in class_to_idx:
                  skipped += 1
                  continue

              bbox = obj["bbox"]
              xmin, ymin = bbox["xmin"], bbox["ymin"]
              xmax, ymax = bbox["xmax"], bbox["ymax"]

              # Convert to YOLO format (normalized center coordinates and dimensions)
              x_center = ((xmin + xmax) / 2.0) / img_width
              y_center = ((ymin + ymax) / 2.0) / img_height
              width = (xmax - xmin) / img_width
              height = (ymax - ymin) / img_height

              # Clip to valid range
              x_center = max(0, min(1, x_center))
              y_center = max(0, min(1, y_center))
              width = max(0, min(1, width))
              height = max(0, min(1, height))

              cls_idx = class_to_idx[category]
              lines.append(f"{cls_idx} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")

          # Write label file
          if lines:
              label_file.write_text("".join(lines), encoding="utf-8")

      if skipped:
          print(f"Skipped {skipped} annotations with unknown categories")
      print("Conversion complete!")

  # Download
  dir = Path(yaml["path"])  # dataset root dir
  urls = ["https://cg.cs.tsinghua.edu.cn/traffic-sign/data_model_code/data.zip"]
  download(urls, dir=dir, curl=True, threads=1)

  # Convert
  tt100k2yolo(dir)

使用方法

若要在 TT100K 数据集上训练 YOLO26 模型 100 个 epoch,且图像尺寸为 640,你可以使用以下代码片段。首次使用时,数据集将自动下载并转换为 YOLO 格式。

训练示例
from ultralytics import YOLO

# Load a model
model = YOLO("yolo26n.pt")  # load a pretrained model (recommended for training)

# Train the model - dataset will auto-download on first run
results = model.train(data="TT100K.yaml", epochs=100, imgsz=640)

样本图像和标注

以下是来自 TT100K 数据集的典型示例:

  1. 城市环境:包含不同距离下多个交通标志的街道场景
  2. 高速公路场景:包括限速和方向指示在内的高速道路标志
  3. 复杂交叉路口:紧邻且方向各异的多个标志
  4. 具有挑战性的条件:不同光照(白天/夜晚)、天气(雨/雾)和观察角度下的标志

该数据集包括:

  1. 特写标志:占据图像较大面积的、清晰可见的标志
  2. 远距离标志:需要细粒度检测能力的小型标志
  3. 部分遮挡的标志:被车辆、树木或其他物体部分阻挡的标志
  4. 每图多个标志:包含多个不同类型标志的图像

引文与致谢

如果你在研究或开发工作中使用了 TT100K 数据集,请引用以下论文:

引用
@InProceedings{Zhu_2016_CVPR,
    author = {Zhu, Zhe and Liang, Dun and Zhang, Songhai and Huang, Xiaolei and Li, Baoli and Hu, Shimin},
    title = {Traffic-Sign Detection and Classification in the Wild},
    booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)},
    month = {June},
    year = {2016}
}

我们感谢清华大学和腾讯的合作,为计算机视觉和自动驾驶社区创建并维护了这一宝贵资源。有关 TT100K 数据集的更多信息,请访问官方数据集网站

常见问题 (FAQ)

TT100K 数据集有什么用途?

Tsinghua-Tencent 100K (TT100K) 数据集专为真实场景下的交通标志检测和分类而设计。它主要用于:

  1. 训练自动驾驶感知系统
  2. 开发高级驾驶辅助系统 (ADAS)
  3. 在多变条件下进行稳健目标检测的研究
  4. 对交通标志识别算法进行基准测试
  5. 测试模型对大图像中小型目标的检测性能

凭借 100,000 张多样的街景图像和 221 个交通标志类别,它为真实场景下的交通标志检测提供了一个综合测试平台。

TT100K 中有多少个交通标志类别?

TT100K 数据集包含 221 个不同的交通标志类别,包括:

  1. 限速标志:pl5 到 pl120(禁止限速)以及 pm5 到 pm55(最低限速)
  2. 禁令标志:28 种以上的常规禁止类型 (p1-p28) 以及限制标志 (pr*, pn, pne)
  3. 警告标志:60 种以上的警告类别 (w1-w66)
  4. 限高/限宽标志:用于物理限制的 ph* 和 pb* 系列
  5. 指示标志:i1-i15, il*, io, ip,用于引导和信息提供

这一全面覆盖包含了中国道路网络中发现的大部分交通标志。

我该如何使用 TT100K 数据集训练 YOLO26n 模型?

若要在 TT100K 数据集上训练 YOLO26n 模型 100 个 epoch,且图像尺寸为 640,请参考下面的示例。

训练示例
from ultralytics import YOLO

# Load a model
model = YOLO("yolo26n.pt")  # load a pretrained model (recommended for training)

# Train the model
results = model.train(data="TT100K.yaml", epochs=100, imgsz=640)

有关详细的训练配置,请参阅训练文档。

与其它数据集相比,TT100K 的挑战性在哪里?

TT100K 带来了几个独特的挑战:

  1. 尺度变化:标志尺寸跨度从非常小(远距离高速公路标志)到很大(城市特写标志)
  2. 真实世界条件:光照、天气和观察角度的极端变化
  3. 高分辨率:2048×2048 像素的图像需要大量的处理能力
  4. 类别不平衡:某些类型的标志比其它类型常见得多
  5. 密集场景:单个图像中可能出现多个标志
  6. 部分遮挡:标志可能被车辆、植被或结构物部分阻挡

这些挑战使得 TT100K 成为开发稳健检测算法的宝贵基准。

我该如何处理 TT100K 中较大的图像尺寸?

TT100K 数据集使用 2048×2048 像素的图像,这可能会占用大量资源。以下是推荐的策略:

用于训练:

# Option 1: Resize to standard YOLO size
model.train(data="TT100K.yaml", imgsz=640, batch=16)

# Option 2: Use larger size for better small object detection
model.train(data="TT100K.yaml", imgsz=1280, batch=4)

# Option 3: Multi-scale training
model.train(data="TT100K.yaml", imgsz=640, scale=0.5)  # trains at varying scales

建议:

  • imgsz=640 开始进行初步实验
  • 如果 GPU 内存充足(24GB+),请使用 imgsz=1280
  • 考虑针对极小标志采用切片策略
  • 使用梯度累加来模拟更大的批次大小

评论