YOLO5用于交通标志牌(TT100K数据集)的训练预测(包含数据集格式的转换——TT100K-CoCo格式-YOLO格式,数据集比例的重新划分以及对应图片集的重新划分)

2023-11-14

先贴下实验结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
去年就做完了的一个工作,这会终于记录完毕啦。

另外如果是对口罩识别检测(可用于毕设、课程设计等等)感兴趣的同学也可参考博主的另一篇博文口罩识别检测;同类型的火灾识别检测(提供标注好的YOLO格式数据集或训练好的权重),有需求的可以私信博主。

一、数据集转换

1.1、数据集下载

下载地址:TT100K

1.2、数据集格式转换

1.2.1. 下载数据集通过以下Python脚本进行数据集格式转换。

import os
import json
from random import random
import cv2
import shutil
import json
import xml.dom.minidom
from tqdm import tqdm
import argparse


# from jinxSkills.jinx_opencv.datasets_transform.dataset_transform import DataSets_transform


class TT100K2COCO:
    def __init__(self):
        self.original_datasets = 'tt100k'
        self.to_datasets = 'coco'

    def class_statistics(self):
        # os.makedirs('annotations', exist_ok=True)
        # 存放数据的父路径
        parent_path = 'D:/jinxData/TT100K/data'

        # 读TT100K原始数据集标注文件
        with open(os.path.join(parent_path, 'annotations.json')) as origin_json:
            origin_dict = json.load(origin_json)
            classes = origin_dict['types']
        # 建立统计每个类别包含的图片的字典
        sta = {}
        for i in classes:
            sta[i] = []

        images_dic = origin_dict['imgs']

        # 记录所有保留的图片
        saved_images = []
        # 遍历TT100K的imgs
        for image_id in images_dic:
            image_element = images_dic[image_id]
            image_path = image_element['path']

            # 添加图像的信息到dataset中
            image_path = image_path.split('/')[-1]
            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的类别(重新划分,阈值100可根据需求修改)
        result = {k: v for k, v in sta.items() if len(v) >= 100}

        for i in result:
            print("the type of {} includes {} images".format(i, len(result[i])))
            saved_images.extend(result[i])

        saved_images = list(set(saved_images))
        print("total types is {}".format(len(result)))

        type_list = list(result.keys())
        result = {"type": type_list, "details": result, "images": saved_images}
        print(type_list)
        # 保存结果
        json_name = os.path.join(parent_path, 'statistics.json')
        with open(json_name, 'w', encoding="utf-8") as f:
            json.dump(result, f, ensure_ascii=False, indent=1)

    def original_datasets2object_datasets(self):
        # os.makedirs('dataset/annotations', exist_ok=True)
        # 存放数据的父路径
        parent_path = 'D:/jinxData/TT100K/data'

        # 读TT100K原始数据集标注文件
        with open(os.path.join(parent_path, 'annotations.json')) as origin_json:
            origin_dict = json.load(origin_json)

        with open(os.path.join(parent_path, 'statistics.json')) 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 = {}

        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'] = info
        val_dataset['info'] = info
        test_dataset['info'] = info
        train_dataset['licenses'] = licenses
        val_dataset['licenses'] = licenses
        test_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] = i

        images_dic = origin_dict['imgs']

        obj_id = 1

        # TT100K的annotation转换成coco的
        for image_id in images_dic:
            image_element = images_dic[image_id]
            image_path = image_element['path']

            # 用opencv读取图片,得到图像的宽和高
            im = cv2.imread(os.path.join(parent_path, image_path))
            H, W, _ = im.shape

            # 切换dataset的引用对象,从而划分数据集
            if 'train' in image_path:
                dataset = train_dataset
            elif 'test' in image_path:
                dataset = val_dataset
            else:
                dataset = test_dataset

            # 添加图像的信息到dataset中
            image_path = image_path.split('/')[-1]
            dataset['images'].append({'file_name': image_path,
                                      'id': image_id,
                                      'width': W,
                                      'height': H})
            obj_list = image_element['objects']

            for anno_dic in obj_list:
                x = 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,
                    # mask, 矩形是从左上角点按顺时针的四个顶点
                    'segmentation': [[x, y, x + width, y, x + width, y + height, x, y + height]]
                })
                # 每个标注的对象id唯一
                obj_id += 1

        # 保存结果
        for phase in ['train', 'val', 'test']:
            json_name = os.path.join(parent_path, 'annotations/{}.json'.format(phase))
            with open(json_name, 'w', encoding="utf-8") as f:
                if phase == 'train':
                    json.dump(train_dataset, f, ensure_ascii=False, indent=1)
                if phase == 'val':
                    json.dump(val_dataset, f, ensure_ascii=False, indent=1)
                if phase == 'test':
                    json.dump(test_dataset, f, ensure_ascii=False, indent=1)

    def original_datasets2object_datasets_re(self):
        '''
        重新划分数据集
        :return:
        '''
        # os.makedirs('annotations2', exist_ok=True)
        # 存放数据的父路径
        parent_path = 'D:/jinxData/TT100K/data'

        # 读TT100K原始数据集标注文件
        with open(os.path.join(parent_path, 'annotations.json')) as origin_json:
            origin_dict = json.load(origin_json)

        with open(os.path.join(parent_path, 'statistics.json')) 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 = {}  # 记录每个标志类别的id
        count = {}  # 记录每个类别的图片数
        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'] = info
        val_dataset['info'] = info
        test_dataset['info'] = info
        train_dataset['licenses'] = licenses
        val_dataset['licenses'] = licenses
        test_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] = i
            count[cls] = 0
            owntype_sum[cls] = 0

        images_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']
            # 记录图片中包含最多的实例所属的type
            includes_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"]] += 1
                else:
                    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转换成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']:
                continue
            print("dealing with {} image".format(image_path))
            # shutil.copy(os.path.join(parent_path,image_path),os.path.join(parent_path,"dataset/JPEGImages"))

            # 处理TT100K中的标注信息
            obj_list = image_element['objects']
            # 记录图片中包含最多的实例所属的type
            includes_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"]] += 1
                else:
                    includes_type[anno_dic["category"]] = 1
            # print(includes_type)
            own_type = max(includes_type, key=includes_type.get)
            count[own_type] += 1
            num_rate = count[own_type] / owntype_sum[own_type]

            # 切换dataset的引用对象,从而划分数据集根据每个类别类别的总数量按7:2:1分为了train_set,val_set,test_set。
            # 其中每个图片所属类别根据该图片包含的类别的数量决定(归属为含有类别最多的类别)
            if num_rate < 0.7:
                dataset = train_dataset
            elif num_rate < 0.9:
                dataset = val_dataset
            else:
                print("dataset=test_dataset")
                dataset = test_dataset

            for anno_dic in obj_list:
                if anno_dic["category"] not in select_dict["type"]:
                    continue
                x = 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,
                    # mask, 矩形是从左上角点按顺时针的四个顶点
                    'segmentation': [[x, y, x + width, y, x + width, y + height, x, y + height]]
                })
                # 每个标注的对象id唯一
                obj_id += 1

            # 用opencv读取图片,得到图像的宽和高
            im = cv2.imread(os.path.join(parent_path, image_path))
            # print(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']:
            json_name = os.path.join(parent_path, 'dataset/annotations/{}.json'.format(phase))
            with open(json_name, 'w', encoding="utf-8") as f:
                if phase == 'train':
                    json.dump(train_dataset, f, ensure_ascii=False, indent=1)
                if phase == 'val':
                    json.dump(val_dataset, f, ensure_ascii=False, indent=1)
                if phase == 'test':
                    json.dump(test_dataset, f, ensure_ascii=False, indent=1)

    def json2xml(self):
        img_path = 'F:/tt100k_dataset/data/train/'  # train图片路径
        annos = json.loads(open("F:/tt100k_dataset/data/annotations.json").read())
        xml_path = 'F:/tt100k_dataset/data/xml_train/'  # xml保存路径

        for line in open(img_path + "ids.txt"):
            img_name = line.replace('\n', '')
            img_file = img_name + '.jpg'
            img = cv2.imread(img_path + img_file)
            sp = img.shape
            img_height = str(sp[0])  # height(rows) of image
            img_width = str(sp[1])

            doc = xml.dom.minidom.Document()
            # creat a root node which name is annotation
            annotation = doc.createElement('annotation')
            # add the root node to the dom document object
            doc.appendChild(annotation)

            # add the folder subnode
            folder = doc.createElement('folder')
            folder_text = doc.createTextNode('JPEGImages')
            folder.appendChild(folder_text)
            annotation.appendChild(folder)

            # add the filename subnode
            filename = doc.createElement('filename')
            filename_text = doc.createTextNode(img_file)
            filename.appendChild(filename_text)
            annotation.appendChild(filename)

            # add the path subnode
            path = doc.createElement('path')
            path_text = doc.createTextNode(
                img_path + img_file)
            path.appendChild(path_text)
            annotation.appendChild(path)

            # add the source subnode
            source = doc.createElement('source')
            database = doc.createElement('database')
            database_text = doc.createTextNode('Unknown')
            source.appendChild(database)
            database.appendChild(database_text)
            annotation.appendChild(source)

            # add the size subnode
            size = doc.createElement('size')
            width = doc.createElement('width')
            width_text = doc.createTextNode(img_width)
            height = doc.createElement('height')
            height_text = doc.createTextNode(img_height)
            depth = doc.createElement('depth')
            depth_text = doc.createTextNode('3')
            size.appendChild(width)
            width.appendChild(width_text)
            size.appendChild(height)
            height.appendChild(height_text)
            size.appendChild(depth)
            depth.appendChild(depth_text)
            annotation.appendChild(size)

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

            img_objects = annos["imgs"][img_name]['objects']
            for i in range(0, len(img_objects)):
                obj_category = annos["imgs"][img_name]['objects'][i]['category']
                obj_bbox = annos["imgs"][img_name]['objects'][i]['bbox']
                bbox_ymin = int(annos["imgs"][img_name]['objects'][i]['bbox']['ymin'])
                bbox_xmin = int(annos["imgs"][img_name]['objects'][i]['bbox']['xmin'])
                bbox_ymax = int(annos["imgs"][img_name]['objects'][i]['bbox']['ymax'])
                bbox_xmax = int(annos["imgs"][img_name]['objects'][i]['bbox']['xmax'])
                print(obj_category, bbox_ymin, bbox_xmin, bbox_ymax, bbox_xmax)

                object = doc.createElement('object')
                name = doc.createElement('name')
                name_text = doc.createTextNode(obj_category)
                difficult = doc.createElement('difficult')
                difficult_text = doc.createTextNode('0')
                pose = doc.createElement('pose')
                pose_text = doc.createTextNode('Unspecified')
                truncated = doc.createElement('truncated')
                truncated_text = doc.createTextNode('0')
                bndbox = doc.createElement('bndbox')
                xmin = doc.createElement('xmin')
                xmin_text = doc.createTextNode(str(bbox_xmin))
                ymin = doc.createElement('ymin')
                ymin_text = doc.createTextNode(str(bbox_ymin))
                xmax = doc.createElement('xmax')
                xmax_text = doc.createTextNode(str(bbox_xmax))
                ymax = doc.createElement('ymax')
                ymax_text = doc.createTextNode(str(bbox_ymax))
                object.appendChild(name)
                name.appendChild(name_text)
                object.appendChild(pose)
                pose.appendChild(pose_text)
                object.appendChild(truncated)
                truncated.appendChild(truncated_text)
                object.appendChild(difficult)
                difficult.appendChild(difficult_text)
                object.appendChild(bndbox)
                bndbox.appendChild(xmin)
                xmin.appendChild(xmin_text)
                bndbox.appendChild(ymin)
                ymin.appendChild(ymin_text)
                bndbox.appendChild(xmax)
                xmax.appendChild(xmax_text)
                bndbox.appendChild(ymax)
                ymax.appendChild(ymax_text)
                annotation.appendChild(object)
            fp = open(xml_path + '%s.xml' % img_name, 'w+')
            doc.writexml(fp, indent='\t', addindent='\t', newl='\n', encoding='utf-8')
            # print(annos["imgs"][img_name]['objects'])
        fp.close()

    def coco_json2yolo_txt(self, class_json):
        # COCO 格式的数据集转化为 YOLO 格式的数据集
        # --json_path 输入的json文件路径
        # --save_path 保存的文件夹名字,默认为当前目录下的labels。

        '''
        parser = argparse.ArgumentParser()
        # 这里根据自己的json文件位置,换成自己的就行
        parser.add_argument('--json_path',
                            default='D:/jinxData/TT100K/data/dataset/annotations/train.json',
                            type=str, help="input: coco format(json)")
        # 这里设置.txt文件保存位置
        parser.add_argument('--save_path', default='D:/jinxData/TT100K/data/dataset/annotations', type=str,
                            help="specify where to save the output dir of labels")
        arg = parser.parse_args()
        '''

        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]
            h = box[3]
            # 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)

        # class_json = 'train'
        json_file = os.path.join(
            'D:/jinxData/TT100K/data/dataset/annotations/%s.json' % class_json)  # COCO Object Instance 类型的标注
        # ana_txt_save_path = 'D:/jinxData/TT100K/data/dataset/annotations/train'  # 保存的路径
        ana_txt_save_path = os.path.join('D:/jinxData/TT100K/data/dataset/annotations', 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.txt
            for i, category in enumerate(data['categories']):
                f.write(f"{category['name']}\n")
                id_map[category['id']] = i
        # print(id_map)
        # 这里需要根据自己的需要,更改写入图像相对路径的文件位置。
        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()
            # 将图片的相对路径写入train2017或val2017的路径
            list_file.write('/%s/%s.jpg\n' % (class_json.format(), head))
        list_file.close()

    def divide_TrainValTest(self, source, target):
        '''
        创建文件路径
        :param source: 源文件位置
        :param target: 目标文件位置
        '''
        for i in ['train', 'val', 'test']:
            path = target + '/' + i
            if not os.path.exists(path):
                os.makedirs(path)

        # 遍历目录下的文件名,复制对应的图片到指定目录
        for root, dirs, files in os.walk(source):
            for file in files:
                file_name = os.path.splitext(file)[0]
                image_path = os.path.join(file_name + '.jpg')
                # print(source)
                if 'train' in source:
                    shutil.copyfile('D:/jinxData/TT100K/data/image_reparation/'
                                    + image_path, target + '/train/' + image_path)
                elif 'val' in source:
                    shutil.copyfile('D:/jinxData/TT100K/data/image_reparation/'
                                    + image_path, target + '/val/' + image_path)
                elif 'test' in source:
                    shutil.copyfile('D:/jinxData/TT100K/data/image_reparation/'
                                    + image_path, target + '/test/' + image_path)

    def xml2txt(self):
        # coding:utf-8

        parser = argparse.ArgumentParser()
        # xml文件的地址,根据自己的数据进行修改 xml一般存放在Annotations下
        parser.add_argument('--xml_path', default='xml', type=str, help='input xml label path')
        # 数据集的划分,地址选择自己数据下的ImageSets/Main
        parser.add_argument('--txt_path', default='dataSet', type=str, help='output txt label path')
        opt = parser.parse_args()

        trainval_percent = 1.0
        train_percent = 0.9
        xmlfilepath = opt.xml_path
        txtsavepath = opt.txt_path
        total_xml = os.listdir(xmlfilepath)
        if not os.path.exists(txtsavepath):
            os.makedirs(txtsavepath)

        num = len(total_xml)
        list_index = range(num)
        tv = int(num * trainval_percent)
        tr = int(tv * train_percent)
        trainval = random.sample(list_index, tv)
        train = random.sample(trainval, tr)

        file_trainval = open(txtsavepath + '/trainval.txt', 'w')
        file_test = open(txtsavepath + '/test.txt', 'w')
        file_train = open(txtsavepath + '/train.txt', 'w')
        file_val = open(txtsavepath + '/val.txt', 'w')

        for i in list_index:
            name = total_xml[i][:-4] + '\n'
            if i in trainval:
                file_trainval.write(name)
                if i in train:
                    file_train.write(name)
                else:
                    file_val.write(name)
            else:
                file_test.write(name)

        file_trainval.close()
        file_train.close()
        file_val.close()
        file_test.close()


if __name__ == '__main__':
    tt100k = TT100K2COCO()
    # tt100k.class_statistics()
    # tt100k.original_datasets2object_datasets_re()
    # tt100k.coco_json2yolo_txt('val')
    tt100k.divide_TrainValTest('D:/jinxData/TT100K/data/dataset/annotations/test', 'D:/jinxData/TT100K/data/dataset')

函数tt100k.class_statistics()方法中可以对TT100K中的数据集进行预处理,代码中是只保留包含图片数超过100的类别;

函数tt100k.original_datasets2object_dataset_rs()可以对TT100K数据集的训练集、验证集和测试集进行比例划分;

函数tt100k.coco_json2yolo_txt()将分别将CoCo格式的标签json文件(3个json文件)转换为YOLO格式的txt(注意此处需要分别调用三次,train、val和test,对应生成其3个.txt文件);

函数tt100k.divide_TrainValTest()根据重新划分的结果对原始数据集的图像进行重新划分存储为与标签一一对应的格式,这一步结束即可将重新规划后的数据集以及标签文件整理为数据集通过YOLO5进行训练预测。
如图:
在这里插入图片描述
转换后为如图三个文件夹:在这里插入图片描述
在这里插入图片描述
1.2.2. 数据集层级划分

  1. 通过2.1后对生成的数据进行归纳整理,首先根目录在YOLO层级下的dataset目录:
    在这里插入图片描述
  2. 图里为博主重新整理过后的TK100K数据集:
    在这里插入图片描述
  3. 两个目录,一个是原图片集——images,一个是标签文件——labels:

在这里插入图片描述

  1. image目录下依然是三个文件夹:
    在这里插入图片描述
    里边是对应的原始图片:
    在这里插入图片描述
  2. labels目录下也对应三个文件夹(图里另外两个文件可忽略,):
    在这里插入图片描述
    里边对应为每个图片的标签信息:
    在这里插入图片描述
    至此,数据集准备完毕。

二、训练预测

2.1、.yaml文件创建

需要新建一个.yaml文件用于程序读取数据,如图:

在这里插入图片描述

2.2 训练预测

此处根据YOLO5的官方文档进行训练预测即可。

训练完成后的预测结果展示:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、写在最末

在这里插入图片描述

  • 对于刚接触这个的小白同学,如果有什么环境配置等问题也可以私信博主;
  • 如果不想自己运行,想要已经跑好的数据集或者权重文件直接提供给YOLO的同学,私信博主(非无偿)。另外,TT100K本身包含的标志牌类别一共有200+,但其各类别数量分配不均衡,博主贴的训练结果是选取的个类别实例数大于100的,一共有42类,如果有同学需要自定义比例的数据集也可私信博主。

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

YOLO5用于交通标志牌(TT100K数据集)的训练预测(包含数据集格式的转换——TT100K-CoCo格式-YOLO格式,数据集比例的重新划分以及对应图片集的重新划分) 的相关文章

  • 翠儿。让流永远运行

    我对 tweepy python 库比较陌生 我想确保我的流 python 脚本始终在远程服务器上运行 因此 如果有人能够分享如何实现这一目标的最佳实践 那就太好了 现在我正在这样做 if name main while True try
  • 没有任何元数据的 zip 文件

    我想找到一种简单的方法来压缩一堆文件 而无需任何文件元数据 例如时间戳 这zip命令似乎总是保留元数据 我没有找到禁用元数据的方法 我希望解决方案是一个命令或最多一个 python 脚本 谢谢 正如一些帖子已经指出的那样 zip 标头中的大
  • 从正在运行的 python 脚本检测优化标志是否为 -O 或 -OO

    有时我想生成一个子进程 其优化标志与启动父进程时使用的优 化标志相同 我可以使用类似的东西 optimize not debug 但这样我就可以匹配两者 O and OO flags 是否有一些 python 内部状态包含该信息 经过一番深
  • 行未从树视图复制

    该行未在树视图中复制 我在按行并复制并粘贴到未粘贴的任何地方后制作了弹出复制 The code popup tk Menu tree opportunity tearoff 0 def row copy item tree opportun
  • 在python中将文本文件解析为列表

    我对 Python 完全陌生 我正在尝试读取包含单词和数字组合的 txt 文件 我可以很好地读取 txt 文件 但我正在努力将字符串转换为我可以使用的格式 import matplotlib pyplot as plt import num
  • 如何从 PyCharm 项目中获取我的“exe”[重复]

    这个问题在这里已经有答案了 通过 PyCharm 在 Python 上编写一些项目 我想从中获取一个exe文件 我尝试过 另存为 gt XXX exe 但是 当我尝试执行它时出现错误 此类操作系统不支持该文件 附注 我有win7 x64 它
  • 带图像的简单 GUI [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我试图在简单的 GUI 上显示一些卡
  • sudo pip install python-Levenshtein 失败,错误代码 1

    我正在尝试在 Linux 上安装 python Levenshtein 库 但每当我尝试通过以下方式安装它时 sudo pip install python Levenshtein 我收到此错误 命令 usr bin python c 导入
  • 定义函数后对其进行修饰?

    I think答案是否定的 但我似乎找不到明确的说法 我有以下情况 def decorated function function functools wraps function def my function print Hello s
  • Python Kivy - 在本机网络浏览器中打开 url 的应用程序

    我尝试制作一个简单的应用程序 在单击 Screen One 上的按钮后 在 Kivy 中打开一个网页 我使用了这个主题 Python 在应用程序中直接显示网络浏览器 iframe https stackoverflow com questi
  • 在径向(树)网络x图中查找末端节点(叶节点)

    给定下图 是否有一种方便的方法来仅获取末端节点 我所说的端节点是指那些具有一个连接边的到节点 我认为这些有时被称为叶节点 G nx DiGraph fromnodes 0 1 1 1 1 1 2 3 4 5 5 5 7 8 9 10 ton
  • 如何通过双击在浏览器中打开 ipynb 文件

    以前 我安装了 Canopy 当时 我只需双击 ipynb 文件并在浏览器中打开它们即可 但是 后来我需要Anaconda 一旦我安装了它 这个功能就没有了 现在我只希望能够简单地双击 ipynb 文件 然后该文件就会在 Firefox 中
  • 具有多个元素的数组的真值是二义性错误吗? Python

    from numpy import from pylab import from math import def TentMap a x if x gt 0 and x lt 0 5 return 2 a x elif x gt 0 5 a
  • Python 中的 @staticmethod 与 @classmethod

    方法和方法有什么区别装饰的 https peps python org pep 0318 with staticmethod http docs python org library functions html staticmethod和
  • 为什么我用 beautifulSoup 刮的时候有桌子,但没有 pandas

    尝试抓取条目页面转换为制表符分隔格式 主要拉出序列和 UniProt 登录号 当我跑步时 url www signalpeptide de index php sess m listspdb bacteria s details id 10
  • Matplotlib Scatter - ValueError:RGBA 序列的长度应为 3 或 4

    我正在尝试为我的功能绘制图表 但不断收到此错误 ValueError RGBA sequence should have length 3 or 4 每当我只有 6 种形状时 代码就可以完美运行 但现在我将其增加到 10 种 它就不起作用了
  • 在 MacO 和 Linux 上安装 win32com [重复]

    这个问题在这里已经有答案了 我的问题很简单 我可以安装吗win32com蟒蛇API pywin32特别是 在非 Windows 操作系统上 我一直在Mac上尝试多个版本pip install pywin32 都失败了 下面是一个例子 如果你
  • 为什么我们应该在 def __init__(self, n) -> None: 中使用 -> ?

    我们为什么要使用 gt in def init self n gt None 我读了以下摘录来自 PEP 484 https www python org dev peps pep 0484 the meaning of annotatio
  • 全局变量是 None 而不是实例 - Python

    我正在处理Python 中的全局变量 代码应该可以正常工作 但是有一个问题 我必须使用全局变量作为类的实例Back 当我运行应用程序时 它说 back is None 这应该不是真的 因为第二行setup 功能 back Back Back
  • 检查字符串是否只有字母和空格 - Python

    试图让 python 返回一个字符串仅包含字母和空格 string input Enter a string if all x isalpha and x isspace for x in string print Only alphabe

随机推荐

  • 使用 appium 进行微信小程序的自动化测试

    目录 前言 微信小程序结构 自动化用例的调整 示例代码 后记 前言 微信小程序是一种流行的移动应用程序 它在移动设备上提供了丰富的功能和用户体验 为了确保微信小程序的质量和稳定性 自动化测试是必不可少的一环 Appium是一个强大的自动化测
  • assert断言(没有返回值,不需要console.log,断言未通过会抛出错误,通过不会抛出错误)

    1 assert value message 保证value是true就不会抛出错误 2 assert deepEqual actual expected message 表达式 1 表示测试 actual 参数与 expected 参数是
  • Custom numeric format strings

    string Multiplier Multiplier 0 Console WriteLine string Format Multiplier 1000000 string LiteralChar LiteralChar 0 000 C
  • vue3 图片路径转base64 base64转file(二进制一般后台需要格式) file转base64

    1 图片路径转64 function imageUrlToBase64 url let homeImage new Image 解决跨域问题 homeImage setAttribute crossOrigin anonymous home
  • 为什么前端监控要用GIF打点

    1背景 我们知道 目前主流的前端监控 百度统计 友盟 谷歌统计 都在用GIF进行打点 但是 为什么这些系统都会使用GIF 难道是因为没有其他的解决方案吗 这得从前端监控的原理说起 2前端监控的原理 所谓的前端监控 其实是在满足一定条件后 由
  • DataTable筛选出现异常

    异常详细信息 System ArgumentException 在 Range 对象中 Min 37 必须小于或等于 max 1 解决方法 转化字段类型为int 再次出现问题 HH gt 0 and HH lt 35 出来的数据序列为 1
  • Android Jetpack 之 DataStore

    1 概述 Google 推出了 JetPack 的新成员 DataStore DataStore 是一种新的数据存储方案 DataStore 以异步 一致的事务方式存储数据 克服了 SharedPreferences 的一些缺点 Jetpa
  • 相机标定及点云拼接

    文章目录 前言 一 相机标定原理 二 关键代码 2 1 相机标定代码1 2 2 相机标定代码2 2 3 点云拼接代码 三 结果展示 总结 前言 在上一篇中已经完成了从图像到点云的转换 但是只针对单个相机 在这一篇中将再进一步 从两个相机拍摄
  • 【Python 1-5】Python教程之——详解字符串

    字符串或串 String 是由数字 字母 下划线组成的一串字符 字符串 字符串就是一系列字符 在Python中 用引号括起的都是字符串 其中的引号可以是单引号 也可以是双引号 如下所示 This is a string This is al
  • vba中function(自定义函数)

    自定义函数 顾名思义 就是自己定义的函数 为什么使用自定义函数 exce内置了很多有用的函数 但仍无法满足工作需求 自定义函数的作用 简化复杂的公式 可以和工作表函数相互嵌套使用 Function 函数名 参数1 参数2 代码 函数名 代码
  • Go语言面试题--进阶语法(32)

    文章目录 1 关于 channel 下面描述正确的是 2 下面的代码有什么问题 3 下面的代码有什么问题 4 下面代码输出什么 1 关于 channel 下面描述正确的是 A close 可以用于只接收通道 B 单向通道可以转换为双向通道
  • 大端小端以及内存对齐的优势

    为什么区分大小端 编程语言中不同类型的变量所占的字节大小不一样 大端 低位数据存放在高位地址为大端编码 小端 低位数据存放在低位地址为小端编码 如图所示 对于选择大端小端对程序性能的思考 首先 数据离散程度不同 字节序会在很大程度上影响速度
  • 零基础学习cJSON 源码详解与应用 (三)cJSON_Print();打印json

    文章目录 一 cJSON Print 源码分析 二 print value 2 1 ensure 2 2 print string 2 3 print number 2 4 print array 2 5 print object 三 up
  • 在Windows中使用虚拟机

    文章目录 VirtualBox使用教程 安装教程 获取 CentOS 及版本选择 在虚拟机上安装CentOS 在虚拟机中允许linux系统卡的原因 配置CentOS 安装图形界面系统 X Window System 安装图形界面程序 GNO
  • 版本控制工具

    版本控制工具 版本控制工具如何下拉库里边的内容 从无到有 在SVN中 在本地库中右键单击 选择tortoise SVN 版本库浏览器 然后输入地址 账号密码登录 登陆完毕后选择要下载的文件右键单击选择检出即可下拉到本地库 在GIT中 在本地
  • JQuery纯手搓轮播图【支持自动轮播、划动轮播、圆点联动】

    HTML div class lunbo div class lunbo content div class imgContent img class imgItem activeImg Started src img lunbo01 jp
  • RebornDB:下一代分布式Key-Value数据库

    http www csdn net article 2015 07 13 2825186 现实世界有许多的Key Value数据库 它们都被广泛应用于很多系统 比如 我们能够用Memcached数据库存储一个MySQL查询结果集给后续相同的
  • Thread类的用法 && 线程安全 && 多线程代码案例 && 文件操作和 IO && 网络原理初识 &&UDP socket

    第 1 题 编程题 题目名称 编写代码 实现多线程数组求和 题目内容 给定一个很长的数组 长度 1000w 通过随机数的方式生成 1 100 之间的整数 实现代码 能够创建两个线程 对这个数组的所有元素求和 其中线程1 计算偶数下标元素的和
  • 内存数据库的分布式数据库架构

    author skate time 2012 02 16 转载一篇文章 本文提出了一种通过引入内存数据库层 建立两层多分区分布式数据库架构 此方案用于解决海量高并发系统的数据存储和访问问题 尤其适用于电子商务等数据模型复杂且业务复杂的互联网
  • YOLO5用于交通标志牌(TT100K数据集)的训练预测(包含数据集格式的转换——TT100K-CoCo格式-YOLO格式,数据集比例的重新划分以及对应图片集的重新划分)

    共勉 一 数据集转换 1 1 数据集下载 1 2 数据集格式转换 二 训练预测 三 写在最末 先贴下实验结果 去年就做完了的一个工作 这会终于记录完毕啦 另外如果是对口罩识别检测 可用于毕设 课程设计等等 感兴趣的同学也可参考博主的另一篇博