.txt(yolo)和.xml(VOC)数据集标签格式互相转换

前言:博主在处理目标检测数据集时,经常需要将标签进行不同格式的转换,因此整理了以下代码,以供参考和保存。

一、实现将txt格式转换成xml格式:

# 将txt格式转换成xml格式数据集
from xml.dom.minidom import Document
import os
import cv2


def makexml(picPath, txtPath, xmlPath):  # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径
    """此函数用于将yolo格式txt标注文件转换为voc格式xml标注文件
    在自己的标注图片文件夹下建三个子文件夹,分别命名为picture、txt、xml
    """
    #创建字典用来对类型进行转换,要与classes.txt文件中的类对应,且顺序要一致
    dic = {'0': "person", '1': "car", '2': "bike", '3': "color_cone",
           '4': "car_stop", '5': "bump", '6': "hole", '7': "animal"}
    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] + ".png")      # 注意这里的图片后缀,.jpg/.png
        Pheight, Pwidth, Pdepth = img.shape

        folder = xmlBuilder.createElement("folder")  # folder标签
        foldercontent = xmlBuilder.createTextNode("datasetRGB")
        folder.appendChild(foldercontent)
        annotation.appendChild(folder) 

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

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

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

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

        annotation.appendChild(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) 

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

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

            difficult = xmlBuilder.createElement("difficult")  # difficult标签
            difficultcontent = xmlBuilder.createTextNode("0")
            difficult.appendChild(difficultcontent)
            object.appendChild(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) 

            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) 

            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) 

            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)  

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

            annotation.appendChild(object) 

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


if __name__ == "__main__":
    picPath = "C:\\data\\ir_det_dataset\\Images\\fir\\"  # 图片所在文件夹路径,后面的\\一定要带上
    txtPath = "C:\\data\\ir_det_dataset\\labels\\fir\\"  # txt所在文件夹路径,后面的\\一定要带上
    xmlPath = "C:\\data\\ir_det_dataset\\xml\\fir\\"  # xml文件保存路径,后面的\\一定要带上
    makexml(picPath, txtPath, xmlPath)

转换之后第一行可能会出现,这行代码声明所用的xml版本是1.0,用xml传输数据时的字符编码是utf-8,如果想去除第一行可以采用以下代码:

import os
def file_name(input_dir,output_dir,spile):
         for root, dirs, files in os.walk(input_dir):
             for item in files:
                f = open(input_dir+item, "r", encoding='UTF-8')
                content = f.read()
                content = content.replace('', spile)
                with open(os.path.join(output_dir, item), 'w',encoding='UTF-8') as fval:
                         fval.write(content)
                f.close()
if __name__ == '__main__':
    input_dir = "C:\\data\\ir_det_dataset\\xml\\fir\\"         #旧文件夹
    output_dir = "C:\\data\\ir_det_dataset\\xml\\fir\\xml\\"   #新文件夹
    file_name(input_dir, output_dir, "")

二、实现将txt格式转换成xml格式:

import xml.etree.ElementTree as ET
import os

classes = ["person", "car", "bike", "color_cone", "car_stop", "bump", "hole", "animal"]  

# 和自己classes.txt中的类别要一一对应


def convert(size, box):
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return (x, y, w, h)


def convert_annotation(image_id):

    in_file = open("C:\\data\\ir_det_dataset\\Images\\fir\\xml\\%s.xml" % (image_id), encoding='UTF-8')
    # in_file输入要转换的文件路径

    out_file = open("C:\\data\\ir_det_dataset\\Images\\fir\\txt\\%s.txt" % (image_id), 'w') 
    # out_file输出转换后的文件路径

    tree = ET.parse(in_file)
    root = tree.getroot()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    for obj in root.iter('object'):
        cls = obj.find('name').text
        # print(cls)
        if cls not in classes:
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
             float(xmlbox.find('ymax').text))
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')


CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
xml_path = os.path.join(CURRENT_DIR, "C:\\data\\ir_det_dataset\\Images\\fir\\xml\\")
# xml文件路径

# xml list
img_xmls = os.listdir(xml_path)
for img_xml in img_xmls:
    label_name = img_xml.split('.')[0]
    print(label_name)
    convert_annotation(label_name)

以上代码同时参考了其他博主,第一次发帖如有侵权请联系删除~

你可能感兴趣的:(python,目标检测)