### TT100K 数据集格式转换方法
TT100K 数据集是一种广泛应用于交通标志检测和识别任务的公开数据集[^1]。该数据集通常以特定的标注格式提供,例如 JSON 或 XML 格式。为了将其转换为其他格式(如 COCO、Pascal VOC 或 YOLO 格式),需要对数据集的结构和标注内容进行解析和重构。
以下是一个通用的转换流程及代码示例:
#### 1. 理解 TT100K 数据集的原始格式
TT100K 数据集的标注文件通常以 JSON 格式存储,包含图像路径、类别标签以及边界框信息。例如,一个典型的 JSON 文件可能具有以下结构:
```json
{
"images": [
{
"filename": "image_0001.jpg",
"width": 1920,
"height": 1080,
"regions": [
{
"category": "speedlimit_50",
"bbox": [100, 200, 300, 400]
},
{
"category": "stop",
"bbox": [400, 500, 600, 700]
}
]
}
]
}
```
上述结构中,`regions` 列表包含了每个目标的类别和边界框坐标。
#### 2. 转换为目标格式
##### (1) 转换为 COCO 格式
COCO 格式要求将标注信息组织为 `annotations` 和 `categories` 等字段。以下是一个 Python 示例代码,展示如何将 TT100K 数据集转换为 COCO 格式:
```python
import json
def convert_to_coco(tt100k_json_path, output_path):
with open(tt100k_json_path, 'r') as f:
tt100k_data = json.load(f)
images = []
annotations = []
categories = {}
annotation_id = 1
for image_info in tt100k_data['images']:
image_id = len(images) + 1
images.append({
"id": image_id,
"file_name": image_info["filename"],
"width": image_info["width"],
"height": image_info["height"]
})
for region in image_info["regions"]:
category = region["category"]
if category not in categories:
categories[category] = len(categories) + 1
bbox = region["bbox"]
x, y, w, h = bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]
annotations.append({
"id": annotation_id,
"image_id": image_id,
"category_id": categories[category],
"bbox": [x, y, w, h],
"area": w * h,
"iscrowd": 0
})
annotation_id += 1
coco_data = {
"images": images,
"annotations": annotations,
"categories": [{"id": v, "name": k} for k, v in categories.items()]
}
with open(output_path, 'w') as f:
json.dump(coco_data, f, indent=4)
convert_to_coco("tt100k.json", "coco_output.json")
```
##### (2) 转换为 Pascal VOC 格式
Pascal VOC 格式使用 XML 文件存储标注信息。以下是一个 Python 示例代码,展示如何将 TT100K 数据集转换为 Pascal VOC 格式:
```python
import xml.etree.ElementTree as ET
def create_voc_xml(image_info, output_dir):
root = ET.Element("annotation")
folder = ET.SubElement(root, "folder")
folder.text = "TT100K"
filename = ET.SubElement(root, "filename")
filename.text = image_info["filename"]
size = ET.SubElement(root, "size")
width = ET.SubElement(size, "width")
width.text = str(image_info["width"])
height = ET.SubElement(size, "height")
height.text = str(image_info["height"])
depth = ET.SubElement(size, "depth")
depth.text = "3"
for region in image_info["regions"]:
obj = ET.SubElement(root, "object")
name = ET.SubElement(obj, "name")
name.text = region["category"]
bndbox = ET.SubElement(obj, "bndbox")
xmin = ET.SubElement(bndbox, "xmin")
xmin.text = str(region["bbox"][0])
ymin = ET.SubElement(bndbox, "ymin")
ymin.text = str(region["bbox"][1])
xmax = ET.SubElement(bndbox, "xmax")
xmax.text = str(region["bbox"][2])
ymax = ET.SubElement(bndbox, "ymax")
ymax.text = str(region["bbox"][3])
tree = ET.ElementTree(root)
output_file = f"{output_dir}/{image_info['filename'].split('.')[0]}.xml"
tree.write(output_file)
# 假设 tt100k_data 是加载的 TT100K 数据
for image_info in tt100k_data['images']:
create_voc_xml(image_info, "voc_output")
```
##### (3) 转换为 YOLO 格式
YOLO 格式要求将标注信息存储为 `.txt` 文件,每行表示一个目标的类别和归一化后的边界框坐标。以下是一个 Python 示例代码,展示如何将 TT100K 数据集转换为 YOLO 格式:
```python
def convert_to_yolo(tt100k_json_path, output_dir, class_mapping):
with open(tt100k_json_path, 'r') as f:
tt100k_data = json.load(f)
for image_info in tt100k_data['images']:
output_file = f"{output_dir}/{image_info['filename'].split('.')[0]}.txt"
with open(output_file, 'w') as f:
for region in image_info["regions"]:
category = region["category"]
if category not in class_mapping:
continue
class_id = class_mapping[category]
bbox = region["bbox"]
x_center = (bbox[0] + bbox[2]) / (2 * image_info["width"])
y_center = (bbox[1] + bbox[3]) / (2 * image_info["height"])
width = (bbox[2] - bbox[0]) / image_info["width"]
height = (bbox[3] - bbox[1]) / image_info["height"]
f.write(f"{class_id} {x_center} {y_center} {width} {height}\n")
class_mapping = {"speedlimit_50": 0, "stop": 1}
convert_to_yolo("tt100k.json", "yolo_output", class_mapping)
```
### 注意事项
在执行格式转换时,请确保以下几点:
- 检查原始数据集中是否有缺失或错误的标注信息。
- 确保类别映射正确无误,尤其是在涉及多类别的场景下。
- 在转换过程中,注意边界框坐标的单位一致性(如像素值与归一化值之间的转换)。