TT100K2021数据集标注格式转换

TT100K数据集简介:
TT100K数据集是一个公开的交通标志数据集,由清华大学和腾讯联合发布。下载地址(Tsinghua-Tencent 100K Annotations 2021  (with more classification)):http://cg.cs.tsinghua.edu.cn/traffic-sign/数据集大概17.8G,包含4个文件夹,其中三个文件夹,分别存放的图片是 train文件夹存放了 6107张图片,test 文件夹存放了 3073 张图片,other 存放了7643 张(没标签 没sign的)图片。annotations_all.json存放的是数据集的标注信息。

数据集格式转换 

TT100K 数据集的标注文件以 JSON 格式提供,描述了每张图片中交通标志的边界框坐标和类别标签。例如:

{
  "types": ["pl80", "w9", ...],
  "imgs":{
    "62627": {
      "path": "train/62627.jpg", 
	  "id": 62627, 
	  "objects": [
	    {
	      "bbox": {"xmin": 1580.0, "ymin": 758.667, "xmax": 1638.6667, "ymax": 818.6667}, 
		  "category": "ph5"
	    },
		...
	  ]
    }
	...
}

 转为VOC(标注文件xml结尾)

完整转换代码:

import os
import cv2
import json
import xml.dom.minidom


class TT100K2VOC:
    def __init__(self):
        self.dataset_path: str = 'D:\\TT100K2021'  # 修改为自已存放TT100K2021的目录
        self.json_file: str = 'annotations_all.json'
        self.xml_path: str = 'D:\\TT100K2021\\Annotations'  # VOC标注保存目录

    @staticmethod
    def xml_create_annotations(doc: xml.dom.minidom.Document, image_path: str, dsize: tuple):
        annotation = doc.createElement('annotation')
        doc.appendChild(annotation)

        folder = doc.createElement('folder')
        folder_text = doc.createTextNode('JPEGImages')
        folder.appendChild(folder_text)
        annotation.appendChild(folder)

        filename = doc.createElement('filename')
        filename_text = doc.createTextNode(os.path.basename(image_path))
        filename.appendChild(filename_text)
        annotation.appendChild(filename)

        path = doc.createElement('path')
        path_text = doc.createTextNode(image_path.replace('/', '\\'))
        path.appendChild(path_text)
        annotation.appendChild(path)

        source = doc.createElement('source')
        database = doc.createElement('database')
        database_text = doc.createTextNode('Unknown')
        source.appendChild(database)
        database.appendChild(database_text)
        annotation.appendChild(source)

        size = doc.createElement('size')
        width = doc.createElement('width')
        size.appendChild(width)
        width_text = doc.createTextNode(str(dsize[1]))
        width.appendChild(width_text)
        height = doc.createElement('height')
        size.appendChild(height)
        height_text = doc.createTextNode(str(dsize[0]))
        height.appendChild(height_text)
        depth = doc.createElement('depth')
        size.appendChild(depth)
        depth_text = doc.createTextNode('3')
        depth.appendChild(depth_text)
        annotation.appendChild(size)

        segmented = doc.createElement('segmented')
        segmented_text = doc.createTextNode('0')
        segmented.appendChild(segmented_text)
        annotation.appendChild(segmented)
        return annotation

    @staticmethod
    def xml_create_object(doc: xml.dom.minidom.Document, category: str, bbox: tuple):
        objectNode = doc.createElement('object')

        name = doc.createElement('name')
        objectNode.appendChild(name)
        name_text = doc.createTextNode(category)
        name.appendChild(name_text)

        pose = doc.createElement('pose')
        objectNode.appendChild(pose)
        pose_text = doc.createTextNode('Unspecified')
        pose.appendChild(pose_text)

        truncated = doc.createElement('truncated')
        objectNode.appendChild(truncated)
        truncated_text = doc.createTextNode('0')
        truncated.appendChild(truncated_text)

        difficult = doc.createElement('difficult')
        objectNode.appendChild(difficult)
        difficult_text = doc.createTextNode('0')
        difficult.appendChild(difficult_text)

        box = doc.createElement('bndbox')
        objectNode.appendChild(box)
        x_min = doc.createElement('xmin')
        box.appendChild(x_min)
        x_min_text = doc.createTextNode(str(bbox[0]))
        x_min.appendChild(x_min_text)
        y_min = doc.createElement('ymin')
        box.appendChild(y_min)
        y_min_text = doc.createTextNode(str(bbox[1]))
        y_min.appendChild(y_min_text)
        x_max = doc.createElement('xmax')
        box.appendChild(x_max)
        x_max_text = doc.createTextNode(str(bbox[2]))
        x_max.appendChild(x_max_text)
        y_max = doc.createElement('ymax')
        box.appendChild(y_max)
        y_max_text = doc.createTextNode(str(bbox[3]))
        y_max.appendChild(y_max_text)
        return objectNode

    def json2xml(self):
        json_data = json.loads(open(self.dataset_path + "/" + self.json_file).read())
        images = json_data['imgs']

        for index, image_id in enumerate(images):
            image_data = images[image_id]
            save_xml_dir = os.path.join(self.xml_path, os.path.dirname(image_data['path']))
            os.makedirs(save_xml_dir, exist_ok=True)

            image_path = self.dataset_path + '/' + image_data['path']
            if not os.path.exists(image_path):
                continue
            image = cv2.imread(image_path)

            doc = xml.dom.minidom.Document()
            annotation = self.xml_create_annotations(doc, image_path, image.shape[:2])

            image_objects = image_data['objects']
            for item in image_objects:
                object_category = item['category']
                object_bbox = item['bbox']
                x_min, y_min = int(object_bbox['xmin']), int(object_bbox['ymin'])
                x_max, y_max = int(object_bbox['xmax']), int(object_bbox['ymax'])
                objectNode = self.xml_create_object(doc, object_category, (x_min, y_min, x_max, y_max))
                annotation.appendChild(objectNode)
            print(f'正在处理第{index + 1}个文件:{image_path}')
            xml_file = open(save_xml_dir + '/%s.xml' % image_id, 'w+')
            doc.writexml(xml_file, addindent='\t', newl='\n', encoding='utf-8')
            xml_file.close()


if __name__ == '__main__':
    tt100k = TT100K2VOC()
    tt100k.json2xml()

转为YOLO(标注文件txt结尾)

完整转换代码:

import cv2
import os
import json


class TT100K2YOLO:
    def __init__(self):
        self.dataset_path: str = 'D:\\TT100K2021'  # 下载的TT100K数据集所在目录
        self.json_file: str = 'annotations_all.json'  # TT100K中的标注信息
        self.save_path: str = 'D:\\TT100K2021\\YOLO'  # 转换后的YOLO标注保存目录

    @staticmethod
    def convert(size, box):
        dw = 1. / (size[0])
        dh = 1. / (size[1])
        x = (box[0] + box[2]) / 2.0
        y = (box[1] + box[3]) / 2.0
        w = box[2] - box[0]
        h = box[3] - box[1]
        # round函数确定(xmin, ymin, xmax, ymax)的小数位数
        x = round(x * dw, 6)
        w = round(w * dw, 6)
        y = round(y * dh, 6)
        h = round(h * dh, 6)
        return x, y, w, h

    def json2yolo(self):
        # 读TT100K原始数据集标注文件
        with open(os.path.join(self.dataset_path, self.json_file)) as data_json:
            data_dict = json.load(data_json)
            classes = list(data_dict['types'])
            images = data_dict['imgs']

        for imageId in images:
            objects = images[imageId]['objects']
            if len(objects) == 0:
                continue

            path = images[imageId]['path']
            image_path = self.dataset_path + '/' + path
            if not os.path.exists(image_path):
                continue

            image = cv2.imread(image_path)
            save_dir = os.path.join(self.save_path, os.path.dirname(path))
            os.makedirs(save_dir, exist_ok=True)
            with open(os.path.join(save_dir, imageId + '.txt'), 'w') as txt_file:
                for item in objects:
                    bbox, category = item['bbox'], item['category']
                    box = (bbox['xmin'], bbox['ymin'], bbox['xmax'], bbox['ymax'])
                    x, y, w, h = self.convert(image.shape[:2], box)
                    txt_file.write(f'{classes.index(category)} {x} {y} {w} {h}' + '\n')
            print(f'生成文件:{save_dir + "/" + imageId + ".txt"}')

        with open(os.path.join(self.save_path, 'classes.txt'), 'w') as file:
            for line in classes:
                file.write(line + '\n')


if __name__ == '__main__':
    tt100k = TT100K2YOLO()
    tt100k.json2yolo

03-08
### TT100K 数据集介绍 TT100K 是一个广泛用于交通标志识别研究的大规模图像数据集[^2]。该数据集包含了多种类型的交通标志图片,旨在帮助研究人员开发和评估针对复杂场景下的交通标志检测算法。 #### 数据集特点 - **多样性**: 包含超过九千张不同天气条件、光照环境以及拍摄角度下采集的真实道路环境中出现过的各类常见中国国家标准规定的道路交通指示牌。 - **标注质量高**: 每个实例都经过人工精确定位并分类标记,在此基础上还提供了额外属性信息如遮挡程度等辅助特征描述。 - **应用场景广**: 不仅适用于常规的日间晴朗条件下工作良好,对于夜晚低光度情况或是雨雾恶劣气候状况同样具有很好的适应能力。 ### 使用方法概述 为了使YOLO系列目标检测框架能够有效利用此数据集进行训练,通常需要完成以下几个方面的工作: #### 准备阶段 - 将原始 COCO 格式的标签文件转换为目标检测任务常用的 YOLO txt 文件格式。这一步骤涉及到读取 JSON 形式的注解文档,并按照每一张图对应一行记录的方式写出边界框坐标及其所属类别编号到纯文本文件中去。 ```bash python convert_coco_to_yolo.py --input_json ./annotations/train.json --output_dir ./labels/ ``` 上述命令假设存在名为 `convert_coco_to_yolo.py` 的脚本用来处理这种格式间的互转过程;实际应用时可根据个人需求编写相应工具实现相同功能。 #### 划分子集 考虑到模型泛化能力和过拟合风险之间的权衡关系,合理地把整个集合划分为相互独立而又代表性强的三个部分——即训练集(train)、验证集(val) 和测试集(test),是非常必要的举措之一。一般情况下会遵循如下比例分配原则:大约三分之二作为前者参与参数调整流程之中;剩余三分之一则留作后者来衡量最终性能指标的好坏与否。 | 子集名称 | 图片数量 | | --- | --- | | 训练集 (Train) | 6,793 张 | | 验证集 (Validation) | 1,949 张| | 测试集 (Test)| 996 张 | #### 开始训练 当一切准备工作就绪之后就可以着手构建基于所选架构(此处为YOLOv11)的目标探测器了。此时应当注意设置好超参选项比如学习率大小、批尺寸多少等等因素以确保收敛速度和平稳性均处于理想状态范围内[^1]。 ```yaml # yolov11-tt100k.yaml configuration snippet train: epochs: 300 batch_size: 16 optimizer: lr0: 0.01 dataset: train_path: 'data/tt100k/images/train/' val_path: 'data/tt100k/images/val/' ``` 通过以上配置片段可以看出如何指定路径指向先前准备好的各个分割后的样本库位置以便于后续加载使用。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值