使用Yolov8 训练交通标志数据集:TT100K数据集划分

article/2025/6/19 22:32:09

使用Yolov8 训练交通标志数据集:TT100K数据集划分(一)

  • 一、数据集下载
  • 二、划分数据集
  • 三、目录放置


一、数据集下载

  1. 官方网址:TT100K
    在这里插入图片描述

  2. 数据集对比
    在这里插入图片描述
    源码如下:

    def classes(filedir):with open(filedir) as f:classes = json.load(f)classes_list = classes['types']return len(classes_list)c_2016 = classes("./annotations.json")
    c_2021 = classes("./annotations_all.json")
    print(f'TT100K-2016 交通标志的类别:{c_2016}')
    print(f'TT100K-2021 交通标志的类别:{c_2021}')
    print(f'差值:{c_2021-c_2016}')
    
  3. 查看类别数目

    # 读TT100K原始数据集标注文件
    with open(annotations) as p:# 读取 json 文件file = json.load(p)# 获取图字典img_dict = file['imgs']types = file['types']classes_list = dict()for i in types:# i 为所有的类别: 如:‘pl80’, 'w9', 'p6'# 将每一个类别作为字典中的键,值为: 空列表 []classes_list[i] = 0for img_id in img_dict:img = images_dict[img_id]obj_list = img['objects']# 统计实际有多少种类别for obj in obj_list:classes_list[obj['category']] += 1# 大于0的有201个d = []for keym, val in classes_list.items():if val > 0:d.append(val)print(len(d))
    

二、划分数据集

数据集划分有四个步骤,依次按照一下步骤执行即可:

  1. 获取每个类别有多少图片的 classes_statistics.json 文件。此过程会产生一个 json 文件,保存了分类类别,每个类别的详细信息,以及所有图片信息。
    在这里插入图片描述
    在这里插入图片描述
    源码如下:

    def classes_statistics():"""类别统计函数,统计每一个类别下有多少张图片保存在 classes_statistics.json 文件中:return:"""# 读TT100K原始数据集标注文件with open(annotations) as origin_json:# 读取 json 文件origin_dict = json.load(origin_json)# 获取类别列表classes_list = origin_dict['types']# 获取图字典images_dict = origin_dict['imgs']# 建立统计每个类别包含的图片的字典sta = dict()for i in classes_list:# i 为所有的类别: 如:‘pl80’, 'w9', 'p6'# 将每一个类别作为字典中的键,值为: 空列表 []sta[i] = []# 遍历TT100K的imgsfor image_id in images_dict:image_element = images_dict[image_id]image_path = image_element['path']# 添加图像的信息到dataset中image_path = image_path.split('/')[-1]  # 如:‘62627.jpg’obj_list = image_element['objects']# 遍历每张图片的标注信息,将每张图片的路径添加到对应类别的字典中去for anno_dic in obj_list:label_key = anno_dic['category']# 防止一个图片多次加入一个标签类别if image_path not in sta[label_key]:sta[label_key].append(image_path)# 数据清洗--只保留包含图片数超过100的类别# 清洗之后还剩下:45种类别result = {k: v for k, v in sta.items() if len(v) > 100}# 将所有标注写入文件 此时写入超过100张图片的with open('./all_classes.json', 'w', encoding="utf-8") as f:json.dump(result, f, ensure_ascii=False, indent=2)# 记录所有保留的图片saved_images = []for i in result:saved_images.extend(result[i])# 第二次数据清洗。同一张图片有多个类别标注,所以要去重old_saved_images = len(saved_images)saved_images = list(set(saved_images))new_saved_images = len(saved_images)# print(f"total types is: {len(result)}")type_list = list(result.keys())# 字典,三个键:类型(列表),详细信息(字典),所有类型的图片数据(列表)result2 = {"type": type_list, "details": result, "images": saved_images}# 保存结果json_name = classes_statistics_namewith open(json_name, 'w', encoding="utf-8") as f:json.dump(result2, f, ensure_ascii=False, indent=2)print(f"类别统计文件已保存:{json_name}")return type_list, result, saved_images, result2, old_saved_images, new_saved_images
    

    结果如下:
    在这里插入图片描述

  2. 将 TT100K 原始数据集转换为 COCO 数据集格式,并根据图片中各类别的数量比例将数据划分为训练集、验证集和测试集,以便后续的模型训练和评估。此步骤生成,train.json, test.json, val.json 文件,划分比例为7:2:1。
    源码如下:

    def original_datasets2object_datasets_re():'''重新划分数据集将 TT100K 原始数据集转换为 COCO 数据集格式,并根据图片中各类别的数量比例将数据划分为训练集、验证集和测试集,以便后续的模型训练和评估。:return:'''# 读TT100K原始数据集标注文件with open(annotations) as origin_json:origin_dict = json.load(origin_json)with open(classes_statistics_name) as select_json:select_dict = json.load(select_json)classes = select_dict['type']train_dataset = {'info': {}, 'licenses': [], 'categories': [], 'images': [], 'annotations': []}val_dataset = {'info': {}, 'licenses': [], 'categories': [], 'images': [], 'annotations': []}test_dataset = {'info': {}, 'licenses': [], 'categories': [], 'images': [], 'annotations': []}label = {}  # 记录每个标志类别的idcount = {}  # 记录每个类别的图片数owntype_sum = {}info = {"year": 2021,  # 年份"version": '1.0',  # 版本"description": "TT100k_to_coco",  # 数据集描述"contributor": "Tecent&Tsinghua",  # 提供者"url": 'https://cg.cs.tsinghua.edu.cn/traffic-sign/',  # 下载地址"date_created": 2021 - 1 - 15}licenses = {"id": 1,"name": "null","url": "null",}train_dataset['info'] = infoval_dataset['info'] = infotest_dataset['info'] = infotrain_dataset['licenses'] = licensesval_dataset['licenses'] = licensestest_dataset['licenses'] = licenses# 建立类别和id的关系for i, cls in enumerate(classes):train_dataset['categories'].append({'id': i, 'name': cls, 'supercategory': 'traffic_sign'})val_dataset['categories'].append({'id': i, 'name': cls, 'supercategory': 'traffic_sign'})test_dataset['categories'].append({'id': i, 'name': cls, 'supercategory': 'traffic_sign'})label[cls] = icount[cls] = 0owntype_sum[cls] = 0images_dic = origin_dict['imgs']obj_id = 1# 计算出每个类别共‘包含’的图片数for image_id in images_dic:image_element = images_dic[image_id]image_path = image_element['path']image_name = image_path.split('/')[-1]# 在所选的类别图片中if image_name not in select_dict['images']:continue# 处理TT100K中的标注信息obj_list = image_element['objects']# 记录图片中包含最多的实例所属的typeincludes_type = {}for anno_dic in obj_list:if anno_dic["category"] not in select_dict["type"]:continue# print(anno_dic["category"])if anno_dic["category"] in includes_type:includes_type[anno_dic["category"]] += 1else:includes_type[anno_dic["category"]] = 1# print(includes_type)own_type = max(includes_type, key=includes_type.get)owntype_sum[own_type] += 1# TT100K的annotation_all转换成coco的格式for image_id in images_dic:image_element = images_dic[image_id]image_path = image_element['path']image_name = image_path.split('/')[-1]# 在所选的类别图片中if image_name not in select_dict['images']:continueprint(f"dealing with {image_path} ")# 处理TT100K中的标注信息obj_list = image_element['objects']# 记录图片中包含最多的实例所属的typeincludes_type = {}for anno_dic in obj_list:if anno_dic["category"] not in select_dict["type"]:continue# print(anno_dic["category"])if anno_dic["category"] in includes_type:includes_type[anno_dic["category"]] += 1else:includes_type[anno_dic["category"]] = 1# print(includes_type)own_type = max(includes_type, key=includes_type.get)count[own_type] += 1num_rate = count[own_type] / owntype_sum[own_type]# 划分数据集 7:2:1,train_set,val_set,test_set。if num_rate < 0.7:dataset = train_datasetelif num_rate < 0.9:dataset = val_datasetelse:print("dataset=test_dataset")dataset = test_datasetfor anno_dic in obj_list:if anno_dic["category"] not in select_dict["type"]:continuex = anno_dic['bbox']['xmin']y = anno_dic['bbox']['ymin']width = anno_dic['bbox']['xmax'] - anno_dic['bbox']['xmin']height = anno_dic['bbox']['ymax'] - anno_dic['bbox']['ymin']label_key = anno_dic['category']dataset['annotations'].append({'area': width * height,'bbox': [x, y, width, height],'category_id': label[label_key],'id': obj_id,'image_id': image_id,'iscrowd': 0,'segmentation': [[x, y, x + width, y, x + width, y + height, x, y + height]]})# 每个标注的对象id唯一obj_id += 1im = cv2.imread(os.path.join(datasets_dir, image_path))H, W, _ = im.shape# 添加图像的信息到dataset中dataset['images'].append({'file_name': image_name,'id': image_id,'width': W,'height': H})# 保存结果for phase in ['train', 'val', 'test']:# 创建保存位置的文件夹os.makedirs(RETT100K_dir+'/labels', exist_ok=True)json_name = RETT100K_dir+f'/labels/{phase}.json'with open(json_name, 'w', encoding="utf-8") as f:if phase == 'train':json.dump(train_dataset, f, ensure_ascii=False, indent=2)if phase == 'val':json.dump(val_dataset, f, ensure_ascii=False, indent=2)if phase == 'test':json.dump(test_dataset, f, ensure_ascii=False, indent=2)
    

    执行结果:
    在这里插入图片描述
    在这里插入图片描述

  3. 写入归一化的标注文件, 生成 yolo 格式的标注信息。获取标注信息,并划分 yolo 格式的标注信息 *.txt 文件夹
    源码如下:

    def coco_json2yolo_txt(class_json):# 将标注位置坐标做归一化处理def convert(size, box):dw = 1. / (size[0])dh = 1. / (size[1])x = box[0] + box[2] / 2.0y = box[1] + box[3] / 2.0w = box[2]h = box[3]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)json_file = os.path.join(RETT100K_dir+f'/labels/{class_json}.json')ana_txt_save_path = os.path.join(RETT100K_dir+'labels', class_json)  # 保存的路径data = json.load(open(json_file, 'r'))if not os.path.exists(ana_txt_save_path):os.makedirs(ana_txt_save_path)id_map = {}  # coco数据集的id不连续!重新映射一下再输出!with open(os.path.join(ana_txt_save_path, 'classes.txt'), 'w') as f:# 写入classes.txtfor i, category in enumerate(data['categories']):f.write(f"{category['name']}\n")id_map[category['id']] = i# 写入图像相对路径的文件位置list_file = open(os.path.join(ana_txt_save_path, '%s.txt' % class_json.format()), 'w')for img in tqdm(data['images']):filename = img["file_name"]img_width = img["width"]img_height = img["height"]img_id = img["id"]head, tail = os.path.splitext(filename)ana_txt_name = head + ".txt"  # 对应的txt名字,与jpg一致f_txt = open(os.path.join(ana_txt_save_path, ana_txt_name), 'w')for ann in data['annotations']:if ann['image_id'] == img_id:box = convert((img_width, img_height), ann["bbox"])f_txt.write("%s %s %s %s %s\n" % (id_map[ann["category_id"]], box[0], box[1], box[2], box[3]))f_txt.close()# 将图片的相对路径写入文件list_file.write('/%s/%s.jpg\n' % (class_json.format(), head))list_file.close()
    
    # 3. 写入归一化的标注文件, 生成 yolo 格式的标注信息
    phase=['train', 'val', 'test']
    for phase in phase:coco_json2yolo_txt(phase)
    

    执行结果:
    在这里插入图片描述
    在这里插入图片描述

  4. 拷贝图片,数据集划分完成。
    源码如下:

    def divide_TrainValTest(source, target, pre_datasets):'''创建文件路径并复制数据集:param source: 源文件位置:param target: 目标文件位置:param pre_datasets: 预处理数据集路径'''# 创建输出目录for i in ['train', 'val', 'test']:os.makedirs(f"{target}/{i}", exist_ok=True)# 获取当前处理的数据集类型dataset_type = Noneif 'train' in source:dataset_type = 'train'elif 'val' in source:dataset_type = 'val'elif 'test' in source:dataset_type = 'test'# 收集所有需要处理的文件file_list = []for root, dirs, files in os.walk(source):for file in files:file_name = os.path.splitext(file)[0]# 排除无关项if file_name in ['classes', 'test', 'train', 'val', '10106-checkpoint']:continuefile_list.append(file_name)for file_name in tqdm(file_list, desc=f"处理{dataset_type}数据集", unit="文件"):image_path = f"{file_name}.jpg"source_path = os.path.join(pre_datasets, image_path)target_path = os.path.join(target, dataset_type, image_path)# 复制文件并处理异常try:shutil.copyfile(source_path, target_path)except Exception as e:print(f"警告: 无法复制文件 {image_path}: {e}")print(f"{dataset_type}数据集处理完成!")
    

    执行结果:
    在这里插入图片描述

三、目录放置

  1. 原数据集的目录结构:保持下载时目录不变即可。

    E:\机器学习\TT00K\tt100k_2021>tree
    E:.
    ├─train
    ├─test
    └─other
    
  2. 处理后的数据集目录结:

    E:\机器学习\TT00K\RETT100K_2021>tree
    E:.
    ├─images
    │  ├─test
    │  ├─train
    │  └─val
    └─labels├─test├─train└─val
    
  3. 处理完之后就可以使用 yolo v8/v11 训练了。
    data.yaml 文件如下:

    path: ../datasets/RE_TT100K_2021/
    train: images/train
    val: images/val
    test: images/test# 分类总数
    nc: 45
    # 分类类别
    names: ['pl80', 'p6', 'p5', 'pm55', 'pl60', 'ip', 'p11', 'i2r', 'p23', 'pg', 'il80', 'ph4', 'i4', 'pl70', 'pne', 'ph4.5', 'p12', 'p3', 'pl5', 'w13', 'i4l', 'pl30', 'p10', 'pn', 'w55', 'p26', 'p13', 'pr40', 'pl20', 'pm30', 'pl40', 'i2', 'pl120', 'w32', 'ph5', 'il60', 'w57', 'pl100', 'w59', 'il100', 'p19', 'pm20', 'i5', 'p27', 'pl50']
    

    在这里插入图片描述


END



http://www.hkcw.cn/article/gSmcqdrSpW.shtml

相关文章

【PostgreSQL 03】PostGIS空间数据深度实战:从地图服务到智慧城市

PostGIS空间数据深度实战&#xff1a;从地图服务到智慧城市 关键词 PostGIS, 空间数据库, 地理信息系统, GIS, 空间查询, 地理分析, 位置服务, 智慧城市, 空间索引, 坐标系统 摘要 PostGIS是PostgreSQL的空间数据扩展&#xff0c;它将普通的关系数据库转变为强大的地理信息系统…

Wireshark 使用教程:让抓包不再神秘

一、什么是 tshark&#xff1f; tshark 是 Wireshark 的命令行版本&#xff0c;支持几乎所有 Wireshark 的核心功能。它可以用来&#xff1a; 抓包并保存为 pcap 文件 实时显示数据包信息 提取指定字段进行分析 配合 shell 脚本完成自动化任务 二、安装与验证 Kali Linux…

环境变量Path单行显示改回多行列表显示

环境变量Path单行显示改回多行列表显示 今天去配置环境变量时&#xff0c;双击Path竟然只显示一行&#xff0c;明明记得上次还时一个列表显示来着。由于以前有删除了所有Path变量的经历&#xff0c;所以看到这个情况属实吓我一跳且一脸懵。 仔细地看了一下&#xff0c;Path中…

CodeTop100 Day18

52、最长的有效括号 括号问题需要考虑栈&#xff0c;而最长有效的括号就要考虑动态规划了 这里定义dp[i]为以i-1位置结尾的最长合法括号字串 遍历字符串&#xff0c;当遇到左括号&#xff0c;压入栈&#xff0c;dp[i1]0,遇到右括号&#xff0c;如果栈不为空&#xff0c;配对左…

NLP基础:从词嵌入到预训练模型应用

NLP基础&#xff1a;从词嵌入到预训练模型应用 系统化学习人工智能网站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目录 NLP基础&#xff1a;从词嵌入到预训练模型应用摘要引言一、词嵌入技术&#xff1a;从离散到连续的语义表示1. 传统词嵌…

STM32CubeMX串口配置

STM32CubeMX串口配置 一&#xff0c;Mode1&#xff0c;Asynchronous&#xff08;异步模式&#xff09;2&#xff0c;其他模式3&#xff0c;异步通信中的流控 二&#xff0c;Configuration参数配置(Parameter Settings)1&#xff0c;Basic Parameters2&#xff0c;Advanced Para…

Java内存模型(JMM)与多线程编程实战

最近正在复习Java八股&#xff0c;所以会将一些热门的八股问题&#xff0c;结合ai与自身理解写成博客便于记忆 今天将以这四个问题为依据。 一、JMM内存模型解析 1. JMM核心概念 Java内存模型(Java Memory Model)定义了Java程序中各种变量&#xff08;线程共享变量&#xf…

Spring Cache核心原理与快速入门指南

文章目录 前言一、Spring Cache核心原理1.1 架构设计思想1.2 运行时执行流程1.3 核心组件协作1.4 关键机制详解1.5 扩展点设计1.6 与Spring事务的协同 二、快速入门实战三、局限性3.1 多级缓存一致性缺陷3.2 分布式锁能力缺失3.3 事务集成陷阱 总结 前言 在当今高并发、低延迟…

【设计模式-4.5】行为型——迭代器模式

说明&#xff1a;本文介绍设计模式中&#xff0c;行为型设计模式之一的迭代器模式。 定义 迭代器模式&#xff08;Iterator Pattern&#xff09;&#xff0c;也叫作游标模式&#xff08;Cursor Pattern&#xff09;&#xff0c;它提供一种按顺序访问集合/容器对象元素的方法&…

【Python训练营打卡】day40 @浙大疏锦行

DAY 40 训练和测试的规范写法 知识点回顾&#xff1a; 1. 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中 2. 展平操作&#xff1a;除第一个维度batchsize外全部展平 3. dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropo…

软件技术如何赚钱

1. 开发并销售软件产品​ ​ 独立应用开发&#xff1a;针对特定需求或市场痛点&#xff0c;开发移动应用、桌面软件或网页应用。例如&#xff0c;开发一款专注于时间管理的移动应用&#xff0c;帮助用户提高工作效率。以 Python 结合 Kivy 框架开发一个简单的待办事项应用为例…

【Github/Gitee Webhook触发自动部署-Jenkins】

Github/Gitee Webhook触发自动部署-Jenkins #mermaid-svg-ryhZQMOzmkQZNMwX {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ryhZQMOzmkQZNMwX .error-icon{fill:#552222;}#mermaid-svg-ryhZQMOzmkQZNMwX .error-tex…

华为OD机试真题——最小的调整次数/特异性双端队列(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《最小的调整次数/特异性双端…

建筑兔零基础人工智能自学记录101|Transformer(1)-14

Transformer 谷歌提出&#xff0c;一组编码-解码器 可以同时处理&#xff0c;通过位置编码来处理单词 实质是token词语接龙&#xff08;只是有不同的概率&#xff09; token对应向量 Transformer简述 文生图就需要用到transformer黑箱 token 内部层次 中间主要是embedding…

网线水晶头接法与8根线芯作用解析

网线的正确接法至关重要&#xff0c;它直接影响网络的稳定性与传输速度。而了解每根线的作用&#xff0c;更是深入掌握网络布线知识的关键。常见的网线为非屏蔽双绞线&#xff08;UTP&#xff09;&#xff0c;内部包含 8 根不同颜色的线芯&#xff0c;两两相互缠绕&#xff0c;…

【GESP真题解析】第 2 集 GESP 三级样题卷编程题 1:逛商场

大家好,我是莫小特。 这篇文章给大家分享 GESP 三级样题卷编程题第 1 题:逛商场。 题目链接 洛谷链接:B3848 逛商场 一、完成输入 根据输入格式描述,输入一共有三行,第一行为整数 N,数据范围: 1 ≤ N ≤ 100 1 \le N \le 100 1≤N≤100,使用 int 类型。 第二行为 N …

Nacos实战——动态 IP 黑名单过滤

1、需求分析 一些恶意用户&#xff08;‏可能是黑客、爬虫、DDoS ؜攻击者&#xff09;可能频繁请求服务器资​源&#xff0c;导致资源占用过高。针对这种问题&#xff0c;可以通过IP‏ 封禁&#xff0c;可以有效拉؜黑攻击者&#xff0c;防止资源​被滥用&#xff0c;保障合法…

基于Web的濒危野生动物保护信息管理系统设计(源码+定制+开发)濒危野生动物监测与保护平台开发 面向公众参与的野生动物保护与预警信息系统

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

流媒体协议分析:流媒体传输的基石

在流媒体传输过程中&#xff0c;协议的选择至关重要&#xff0c;它决定了数据如何封装、传输和解析&#xff0c;直接影响着视频的播放质量和用户体验。本文将深入分析几种常见的流媒体传输协议&#xff0c;探讨它们的特点、应用场景及优缺点。 协议分类概述 流媒体传输协议根据…

通过mqtt 发布温湿度

参考 用HAL库改写江科大的stm32入门例子-补充DHT11_江科大stm32安装hal库-CSDN博客 老夫上课的时候 &#xff0c;这部份讲的比较多 &#xff0c;出发点是 安利 “单总线”的具体使用。 这里无非是引入dht11 库&#xff0c; 使用前初始化 然后通话dht11库的方法 读取数据 &…