The VOC format label xml file marked by labelimg and the yolo format label txt file are converted to each other

Table of contents

1 Labelimg label VOC format and yolo format introduction

1.1 voc format

1.2 Introduction to yolo data format

2 Convert between voc format data and yolo format data

2.1 voc to yolo code

2.2 yolo to voc format code 


1 Labelimg label VOC format and yolo format introduction

        How to install and use the labelimg labeling tool has been explained in my blog, you can check it out if you need it, blog .

1.1 voc format

        The VOC format file is saved in the xml file with the same name as the image, and the annotation information in the xml file is shown in the figure below: the red box in the text stores the main information of the annotated image. The first red box shows which folder the picture is saved in, the name of the picture corresponding to the label, and the absolute path to save the picture. The information in the second red box is the size and channel of the label image, which are usually 3 channels. The information in the third red box is the information of the object marked in the figure, which category the target object belongs to. It can be seen that the name of the object is boat, and then there are two points in the marked box, which are respectively box start and end points. The information in the fourth red box is the same as the third box, which is the information of the object we marked, but the object is cat.

1.2 Introduction to yolo data format

        The yolo data format saves the annotation information of each picture in a txt file with the same name as the picture. The information in the txt file is shown in the figure below:

0 0.47416020671834624 0.4523809523809524 0.5968992248062015 0.683982683982684
1 0.874031007751938 0.4069264069264069 0.1227390180878553 0.2727272727272727

        Each line represents a marked object, the first number represents the category of the number, the first type of object is 0, the second type of object is 1, and so on. The following four numbers are the coordinates of the center point of the normalized label and the length and width of the normalized label box.

2 Convert between voc format data and yolo format data

2.1 voc to yolo code

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join


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


def convert_annotation(xml_files_path, save_txt_files_path, classes):
    xml_files = os.listdir(xml_files_path)
    print(xml_files)
    for xml_name in xml_files:
        print(xml_name)
        xml_file = os.path.join(xml_files_path, xml_name)
        out_txt_path = os.path.join(save_txt_files_path, xml_name.split('.')[0] + '.txt')
        out_txt_f = open(out_txt_path, 'w')
        tree = ET.parse(xml_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'):
            difficult = obj.find('difficult').text
            cls = obj.find('name').text
            if cls not in classes or int(difficult) == 1:
                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))
            # b=(xmin, xmax, ymin, ymax)
            print(w, h, b)
            bb = convert((w, h), b)
            out_txt_f.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')


if __name__ == "__main__":
    # 需要转换的类别,需要一一对应
    classes1 = ['boat', 'cat']
    # 2、voc格式的xml标签文件路径
    xml_files1 = r'C:\Users\86159\Desktop\VOC2007\Annotations'
    # 3、转化为yolo格式的txt标签文件存储路径
    save_txt_files1 = r'C:\Users\86159\Desktop\VOC2007\label'

    convert_annotation(xml_files1, save_txt_files1, classes1)

         It should be noted that you must write your own category name correctly and correspond well, otherwise you will make mistakes.

2.2 yolo to voc format code 

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


# def makexml(txtPath, xmlPath, picPath):  # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径
def makexml(picPath, txtPath, xmlPath):  # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径
    """此函数用于将yolo格式txt标注文件转换为voc格式xml标注文件

    在自己的标注图片文件夹下建三个子文件夹,分别命名为picture、txt、xml
    """
    dic = {'0': "boat",  # 创建字典用来对类型进行转换
           '1': "cat",  # 此处的字典要与自己的classes.txt文件中的类对应,且顺序要一致
           }
    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()

if __name__ == "__main__":
    picPath = "C:/Users/86159/Desktop/VOC2007/JPEGImage/"  # 图片所在文件夹路径,后面的/一定要带上
    txtPath = "C:/Users/86159/Desktop/VOC2007/yolo/"  # txt所在文件夹路径,后面的/一定要带上
    xmlPath = "C:/Users/86159/Desktop/VOC2007/Annotations1/"  # xml文件保存路径,后面的/一定要带上
    makexml(picPath, txtPath, xmlPath)

        It should be noted that the category and name must be matched

Guess you like

Origin blog.csdn.net/didiaopao/article/details/119910139