Conversion mutuelle entre les fichiers d'annotation d'ensemble de données lors de la formation de différents modèles de la série yolo

Conversion mutuelle entre les fichiers d'annotation d'ensemble de données lors de la formation de différents modèles de la série yolo

1. Convertissez le fichier json marqué par l'assistant d'annotation au format txt requis pour la formation yolov5. Chaque fichier json doit être parcouru à tour de rôle.

def json2txt():
    from tqdm import tqdm, trange

    ''' 标注精灵的json(x1,y1,x2,y2)文件转训练所用txt(x0,y0,w,h)'''
    
    name2307 = {'pedes': 0, 'car': 1, 'bus': 2, 'bigtru': 3, 'bike': 4, 'elec': 5, 'tricycle': 6, 'coni': 7, 'warm': 8,
               'polic': 1, 'tralight': 9, 'ambu': 10, 'fireen': 10,
              'pedes            ': 0, 'car ': 1, '  car': 1, ' car': 1, ' ca   r': 1, 'suv': 1, 'van': 1,
              'mpv': 1, 'pickup': 1, 'ar': 1, 'pedesd': 0, 'coach ': 2, 'car  ': 1,
              'suv ': 1, 'coach': 2,'trailer': 3, 'crane': 3, 'smatru': 3, 'tank': 3, 'escort': 10,
              'engine': 10, 'bull': 10, 'excava': 10, 'military': 10, 'elec ': 5, 'moto': 5, 'motopoli': 5}
    #name2307 = {#pedes: 0,#car: 1,#bus: 2,#truck: 3,#bike: 4,#elec: 5,#tricycle: 6,#coni: 7,#warm: 8,#tralight: 9,#special_vehicles: 10,}    

    # 如下参数需根据情况进行修改
    namell = name2307
    pathimg =    r'D:\yolov5train\datasTrain3_More\images\val'
    pathjson = r'E:\datasTrainALL\OrdinaryRoad00_outputs44285'
    despathtxt = r'D:\yolov5train\datasTrain3_More\labels\val'

    files = os.listdir(pathimg)
    print(len(files))
    # files = [x for x in files if x[-4:] == '.jpg']
    ic = 0
    ycfile = []
    # for f in files[:]:
    for i in tqdm(range(len(files)), desc='进度:'):
        f = files[i]
        ic = ic + 1
        # print(ic, ':  ', f)

        if (f[-4:] != '.jpg'):
            continue
        imgShape = cv2.imread(os.path.join(pathimg, f)).shape
        imgw, imgh = imgShape[1], imgShape[0]

        json_path_name = os.path.join(pathjson, f[:-4] + '.json')
        with open(json_path_name, 'r', encoding='utf-8') as rf:
            rf = json.load(rf)

            try:
                objs = rf['outputs']['object']
            except:
                ycfile.append(f)
                print(ycfile)
                # break
                continue
            boxs = []
            for o in objs:
                try:
                    id = o['name']
                    if id not in namell.keys():
                        continue
                    id = str(namell[id])
                    xmin = o['bndbox']['xmin']
                    ymin = o['bndbox']['ymin']
                    xmax = o['bndbox']['xmax']
                    ymax = o['bndbox']['ymax']
                    ymax = imgh if (ymax > imgh or (imgh - ymax<5)) else ymax
                    ymin = 0 if  ymin < 5 else ymin
                    xmax = imgw if (xmax > imgw or (imgw - xmax < 5)) else xmax
                    xmin = 0 if xmin < 5 else xmin
                    x = (xmin + xmax) / 2 / imgw
                    y = (ymin + ymax) / 2 / imgh
                    w = (xmax - xmin) / imgw
                    h = (ymax - ymin) / imgh
                    x = str(x) if len(str(x)) <= 7 else str(x)[:7]
                    y = str(y) if len(str(y)) <= 7 else str(y)[:7]
                    w = str(w) if len(str(w)) <= 7 else str(w)[:7]
                    h = str(h) if len(str(h)) <= 7 else str(h)[:7]
                    box = id + ' ' + x + ' ' + y + ' ' + w + ' ' + h + '\n'
                    boxs.append(box)
                except:
                    continue
            if boxs == []:
                continue
            boxs[-1] = boxs[-1].replace('\n', '')

        txt_path_name = os.path.join(despathtxt, f[:-4] + '.txt')
        with open(txt_path_name, 'w', encoding='utf-8') as wf:
            wf.writelines(boxs)

    print(ycfile)

2. Pour convertir le format txt de yolov5 en XML de yolovX, chaque fichier txt doit être parcouru dans l'ordre.

réf :https://zhuanlan.zhihu.com/p/525950939

def txt2xml():
    """
    for YOLOX
    将yolov5的txt格式转化为yolovX的xml
    """
    # ref :https://zhuanlan.zhihu.com/p/525950939

    from xml.dom.minidom import Document
    import os
    import cv2

    """
    此函数用于将yolov5格式txt标注文件转换为voc格式xml标注文件
    在自己的标注图片文件夹下建三个子文件夹
    """
    dic = {'0': "peses",  # 创建字典用来对类型进行转换
           '1': "car",  # 此处的字典要与自己的classes.txt文件中的类对应,且顺序要一致
           '2': "bus",
           '3': "truck",
           '4': "bike",
           '5': "elec",
           '6': "tricycle",
           '7': "coni",
           '8': "warm",
           '9': "tralight",
           '10': "special_vehicle"
           }
    picPath = "D:/yolov5train/datasTrain3_More/images/train/"  # 图片所在文件夹路径,后面的/一定要带上
    txtPath = "D:/yolov5train/datasTrain3_More/labels/train/"  # txt所在文件夹路径,后面的/一定要带上
    xmlPath = "D:/yolov5train/datasTrain3_More/annotations/train/"  # xml文件保存路径,后面的/一定要带上
    files = os.listdir(txtPath)
    for i, name in enumerate(files):
        xmlBuilder = Document()
        annotation = xmlBuilder.createElement("annotation")  # 创建annotation标签
        xmlBuilder.appendChild(annotation)
        txtFile = open(txtPath + name)
        txtList = txtFile.readlines()
        img = cv2.imread(picPath + name[0:-4] + ".jpg")
        Pheight, Pwidth, Pdepth = img.shape

        folder = xmlBuilder.createElement("folder")  # folder标签
        foldercontent = xmlBuilder.createTextNode("driving_annotation_dataset")
        folder.appendChild(foldercontent)
        annotation.appendChild(folder)  # folder标签结束

        filename = xmlBuilder.createElement("filename")  # filename标签
        filenamecontent = xmlBuilder.createTextNode(name[0:-4] + ".jpg")
        filename.appendChild(filenamecontent)
        annotation.appendChild(filename)  # filename标签结束

        size = xmlBuilder.createElement("size")  # size标签
        width = xmlBuilder.createElement("width")  # size子标签width
        widthcontent = xmlBuilder.createTextNode(str(Pwidth))
        width.appendChild(widthcontent)
        size.appendChild(width)  # size子标签width结束

        height = xmlBuilder.createElement("height")  # size子标签height
        heightcontent = xmlBuilder.createTextNode(str(Pheight))
        height.appendChild(heightcontent)
        size.appendChild(height)  # size子标签height结束

        depth = xmlBuilder.createElement("depth")  # size子标签depth
        depthcontent = xmlBuilder.createTextNode(str(Pdepth))
        depth.appendChild(depthcontent)
        size.appendChild(depth)  # size子标签depth结束

        annotation.appendChild(size)  # size标签结束

        for j in txtList:
            oneline = j.strip().split(" ")
            object = xmlBuilder.createElement("object")  # object 标签
            picname = xmlBuilder.createElement("name")  # name标签
            namecontent = xmlBuilder.createTextNode(dic[oneline[0]])
            picname.appendChild(namecontent)
            object.appendChild(picname)  # name标签结束

            pose = xmlBuilder.createElement("pose")  # pose标签
            posecontent = xmlBuilder.createTextNode("Unspecified")
            pose.appendChild(posecontent)
            object.appendChild(pose)  # pose标签结束

            truncated = xmlBuilder.createElement("truncated")  # truncated标签
            truncatedContent = xmlBuilder.createTextNode("0")
            truncated.appendChild(truncatedContent)
            object.appendChild(truncated)  # truncated标签结束

            difficult = xmlBuilder.createElement("difficult")  # difficult标签
            difficultcontent = xmlBuilder.createTextNode("0")
            difficult.appendChild(difficultcontent)
            object.appendChild(difficult)  # difficult标签结束

            bndbox = xmlBuilder.createElement("bndbox")  # bndbox标签
            xmin = xmlBuilder.createElement("xmin")  # xmin标签
            mathData = int(((float(oneline[1])) * Pwidth + 1) - (float(oneline[3])) * 0.5 * Pwidth)
            xminContent = xmlBuilder.createTextNode(str(mathData))
            xmin.appendChild(xminContent)
            bndbox.appendChild(xmin)  # xmin标签结束

            ymin = xmlBuilder.createElement("ymin")  # ymin标签
            mathData = int(((float(oneline[2])) * Pheight + 1) - (float(oneline[4])) * 0.5 * Pheight)
            yminContent = xmlBuilder.createTextNode(str(mathData))
            ymin.appendChild(yminContent)
            bndbox.appendChild(ymin)  # ymin标签结束

            xmax = xmlBuilder.createElement("xmax")  # xmax标签
            mathData = int(((float(oneline[1])) * Pwidth + 1) + (float(oneline[3])) * 0.5 * Pwidth)
            xmaxContent = xmlBuilder.createTextNode(str(mathData))
            xmax.appendChild(xmaxContent)
            bndbox.appendChild(xmax)  # xmax标签结束

            ymax = xmlBuilder.createElement("ymax")  # ymax标签
            mathData = int(((float(oneline[2])) * Pheight + 1) + (float(oneline[4])) * 0.5 * Pheight)
            ymaxContent = xmlBuilder.createTextNode(str(mathData))
            ymax.appendChild(ymaxContent)
            bndbox.appendChild(ymax)  # ymax标签结束

            object.appendChild(bndbox)  # bndbox标签结束

            annotation.appendChild(object)  # object标签结束

        f = open(xmlPath + name[0:-4] + ".xml", 'w')
        xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')
        f.close()

        # break


def ImageSetsMain():
    """
    for YOLOX:将每一个数据文件名称保存在txt文件中
    """
    imgPath = r'D:\yolov5train\datasTrain3_More\images\train'
    xmlPath = r'D:\yolov5train\datasTrain3_More\labels\train'
    train_val_txtPath = r'D:\yolov5train\datasTrain3_More\ImageSets\Main\train.txt'

    imgs = os.listdir(imgPath)
    with open(train_val_txtPath, 'w') as wf:
        for i in range(len(imgs)):
            text = imgs[i].split(".jpg")[0] +'\n'
            wf.write(text)

3. Convertissez le fichier d'annotation au format yolo .txt en fichier d'annotation au format coco .json

import argparse
import json
import os
import sys
import shutil
from datetime import datetime

import cv2

coco = dict()
coco['images'] = []
coco['type'] = 'instances'
coco['annotations'] = []
coco['categories'] = []

category_set = dict()
image_set = set()

image_id = 000000
annotation_id = 0


def addCatItem(category_dict):
    for k, v in category_dict.items():
        category_item = dict()
        category_item['supercategory'] = 'none'
        category_item['id'] = int(k)
        category_item['name'] = v
        coco['categories'].append(category_item)


def addImgItem(file_name, size):
    global image_id
    image_id += 1
    image_item = dict()
    image_item['id'] = image_id
    image_item['file_name'] = file_name
    image_item['width'] = size[1]
    image_item['height'] = size[0]
    image_item['license'] = None
    image_item['flickr_url'] = None
    image_item['coco_url'] = None
    image_item['date_captured'] = str(datetime.today())
    coco['images'].append(image_item)
    image_set.add(file_name)
    return image_id


def addAnnoItem(object_name, image_id, category_id, bbox):
    global annotation_id
    annotation_item = dict()
    annotation_item['segmentation'] = []
    seg = []
    # bbox[] is x,y,w,h
    # left_top
    seg.append(bbox[0])
    seg.append(bbox[1])
    # left_bottom
    seg.append(bbox[0])
    seg.append(bbox[1] + bbox[3])
    # right_bottom
    seg.append(bbox[0] + bbox[2])
    seg.append(bbox[1] + bbox[3])
    # right_top
    seg.append(bbox[0] + bbox[2])
    seg.append(bbox[1])

    annotation_item['segmentation'].append(seg)

    annotation_item['area'] = bbox[2] * bbox[3]
    annotation_item['iscrowd'] = 0
    annotation_item['ignore'] = 0
    annotation_item['image_id'] = image_id
    annotation_item['bbox'] = bbox
    annotation_item['category_id'] = category_id
    annotation_id += 1
    annotation_item['id'] = annotation_id
    coco['annotations'].append(annotation_item)


def xywhn2xywh(bbox, size):
    bbox = list(map(float, bbox))
    size = list(map(float, size))
    xmin = (bbox[0] - bbox[2] / 2.) * size[1]
    ymin = (bbox[1] - bbox[3] / 2.) * size[0]
    w = bbox[2] * size[1]
    h = bbox[3] * size[0]
    box = (xmin, ymin, w, h)
    return list(map(int, box))


def parseXmlFilse(image_path, anno_path, save_path, json_name='train.json'):
    assert os.path.exists(image_path), "ERROR {} dose not exists".format(image_path)
    assert os.path.exists(anno_path), "ERROR {} dose not exists".format(anno_path)
    if os.path.exists(save_path):
        pass
        # shutil.rmtree(save_path)
    os.makedirs(save_path)
    json_path = os.path.join(save_path, json_name)

    category_set = []
    with open(anno_path + '/classes.txt', 'r') as f:
        for i in f.readlines():
            category_set.append(i.strip())
    category_id = dict((k, v) for k, v in enumerate(category_set))
    addCatItem(category_id)

    images = [os.path.join(image_path, i) for i in os.listdir(image_path)]
    files = [os.path.join(anno_path, i) for i in os.listdir(anno_path)]
    images_index = dict((v.split(os.sep)[-1][:-4], k) for k, v in enumerate(images))
    for file in files:
        if os.path.splitext(file)[-1] != '.txt' or 'classes' in file.split(os.sep)[-1]:
            continue
        if file.split(os.sep)[-1][:-4] in images_index:
            index = images_index[file.split(os.sep)[-1][:-4]]
            img = cv2.imread(images[index])
            shape = img.shape
            filename = images[index].split(os.sep)[-1]
            current_image_id = addImgItem(filename, shape)

        else:
            continue
        with open(file, 'r') as fid:
            for i in fid.readlines():
                i = i.strip().split()
                category = int(i[0])
                category_name = category_id[category]
                bbox = xywhn2xywh((i[1], i[2], i[3], i[4]), shape)
                addAnnoItem(category_name, current_image_id, category, bbox)

    json.dump(coco, open(json_path, 'w'))
    print("class nums:{}".format(len(coco['categories'])))
    print("image nums:{}".format(len(coco['images'])))
    print("bbox nums:{}".format(len(coco['annotations'])))





def MultTxt2SingleJson():
    """
        脚本说明:
            本脚本用于将yolo格式的标注文件.txt转换为coco格式的标注文件.json
        参数说明:
            anno_path:标注文件txt存储路径
            save_path:json文件输出的文件夹
            image_path:图片路径
            json_name:json文件名字
        """
    parser = argparse.ArgumentParser()
    parser.add_argument('-ap', '--anno-path', type=str, default=r'D:\yolov5train\datasTrain3_More\labels\val', help='yolo txt path')
    parser.add_argument('-s', '--save-path', type=str, default=r'D:\yolov5train\datasTrain3_More\images\Annotations', help='json save path')
    parser.add_argument('--image-path', default=r'D:\yolov5train\datasTrain3_More\images\val')
    parser.add_argument('--json-name', default='val.json')

    opt = parser.parse_args()
    if len(sys.argv) > 1:
        print(opt)
        parseXmlFilse(**vars(opt))
    else:
        anno_path = r'D:\yolov5train\datasTrain3_More\labels\val'
        save_path = r'D:\yolov5train\datasTrain3_More\images\Annotations'
        image_path = r'D:\yolov5train\datasTrain3_More\images\val'
        json_name = 'val.json'
        parseXmlFilse(image_path, anno_path, save_path, json_name)
    pass

4. Écrivez les chemins d'accès aux fichiers txt pour stocker respectivement les images de l'ensemble de formation et de l'ensemble de validation.

def writeImgPath_forYolov7Datas():
    '''
    因为yolov7训练的时候,在数据集根目录下,需要有txt文件分别存放训练集和验证集图片的路径
    '''
    from tqdm import tqdm
    import os
    imgpath = r'D:/yolov5train/datasTrain3_More/images/train'
    txt_path_name = r'D:/yolov5train/datasTrain3_More/train_list.txt'
    files = os.listdir(imgpath)
    imgspath = []
    for i in tqdm(range(len(files)), desc='进度 '):
        f = files[i]
        try:
            name = os.path.join(imgpath, f)
            name = name + '\n'
            imgspath.append(name)
        except Exception as e:
            print(f, ":", e)
            continue
    imgspath[-1] = imgspath[-1].replace('\n', '')
    with open(txt_path_name, 'w', encoding='utf-8') as wf:
        wf.writelines(imgspath)

5. Convertissez le json de labelme en txt de yolo

def labelmejson2yolotxt():
    import os
    import numpy as np
    from tqdm import tqdm

    imgPath = r' '
    jsonPath = r' '
    savetxtPath = r' '
    clsStatic, clsStaticFlag= {
    
    }, True
    # 先统计标签有哪些再保存txt,根据统计的标签 好确定 namell
    savetxtPath, savetxtPathFlag = savetxtPath, True
    # name15label = [pedes0, car1, bus2, truck3, bike4, elec5, tricycle6, coni7, warm8, tralight9, polic10, ambu11,
    #                fireen12, suv13, mpv14]
    name15 = {
    
    'car': 1, 'suv': 13, 'mpv': 14, 'van': 14, 'polic': 10, 'smatru': 3, 'elec': 5,
              'pedes': 0, 'coni': 7, 'tank': 3, 'moto': 5, 'bigtru': 3, 'bus': 2, 'engine': 3,
              'tricycle': 6, 'pickup': 1, 'coach': 2, 'bike': 4, 'pedesr': 0, 'crane': 3, 'trailer': 3,
              'excava': 3, 'warm': 8, 'tralight': 9, 'truck': 3, 'bigtrur': 3, 'vcar': 1, 'escort': 3 }
    namell =  name15


    files = os.listdir(imgPath)
    print('len(imgPath): ', len(files))
    # files = [x for x in files if x[-4:] == '.jpg']

    for i in tqdm(range(len(files)), desc='进度:'):
        f = files[i]

        if (f[-4:] != '.jpg'):
            continue
        imgShape = cv2.imread(os.path.join(imgPath, f)).shape
        imgw, imgh = imgShape[1], imgShape[0]

        json_path_name = os.path.join(jsonPath, f[:-4] + '.json')
        with open(json_path_name, 'r', encoding='utf-8') as rf:
            rf = json.load(rf)

            try:
                objs = rf['shapes']
            except:
                continue

            boxs = []
            for o in objs:
                try:
                    id = o['label']
                    if clsStaticFlag:
                        if id in clsStatic.keys():
                            clsStatic[id] += 1
                        else:
                            clsStatic[id] = 1
                    if savetxtPathFlag:
                        if id not in namell.keys():
                            continue
                        id = str(namell[id])

                        xmin = o['points'][0][0]
                        ymin = o['points'][0][1]
                        xmax = o['points'][1][0]
                        ymax = o['points'][1][1]

                        ymax = imgh if (ymax > imgh or (imgh - ymax < 5)) else ymax
                        ymin = 0 if ymin < 5 else ymin
                        xmax = imgw if (xmax > imgw or (imgw - xmax < 5)) else xmax
                        xmin = 0 if xmin < 5 else xmin
                        x = (xmin + xmax) / 2 / imgw
                        y = (ymin + ymax) / 2 / imgh
                        w = (xmax - xmin) / imgw
                        h = (ymax - ymin) / imgh
                        x = str(x) if len(str(x)) <= 7 else str(x)[:7]
                        y = str(y) if len(str(y)) <= 7 else str(y)[:7]
                        w = str(w) if len(str(w)) <= 7 else str(w)[:7]
                        h = str(h) if len(str(h)) <= 7 else str(h)[:7]
                        box = id + ' ' + x + ' ' + y + ' ' + w + ' ' + h + '\n'
                        boxs.append(box)
                except Exception as e:
                    print('jie Xi Json Error: ', e)
                    continue
            if boxs == [] and savetxtPathFlag == True:
                continue

        if savetxtPathFlag:
            boxs[-1] = boxs[-1].replace('\n', '')
            txt_path_name = os.path.join(savetxtPath, f[:-4] + '.txt')
            with open(txt_path_name, 'w', encoding='utf-8') as wf:
                wf.writelines(boxs)
    if clsStaticFlag:
        print('clsStatic: ', clsStatic)

        # break



Je suppose que tu aimes

Origine blog.csdn.net/qq_42835363/article/details/131831835
conseillé
Classement