记录Open Image v4数据集转化为VOC格式

先用这段代码进行初步的转化

参考:谷歌Open Image v4数据集按指定类目下载并批量转化为VOC格式 - Anleenoの小屋 (anleenoxu.top)

import math
import shutil

import cv2
from lxml.etree import Element, SubElement, tostring
from xml.dom.minidom import parseString
import os


# 对于每一个label.txt,制作VOC格式的xml文件
# param1:../OID/UnRestraint_Of_MarineCreature_In_OpenImagev4/Dataset/train/Seahorse/
# param2:imglabel.txt
# param3:annotation
def make_xml(txt_root_path, txt_name_path, save_xml_path):
    txt_path = txt_root_path + "Label/" + txt_name_path
    pic_path = txt_root_path
    pic = cv2.imread(pic_path + txt_name_path.replace(".txt", ".jpg"))
    shutil.copy(pic_path + txt_name_path.replace(".txt", ".jpg"), "VOC2007/JPEGImages")
    shape = pic.shape

    f = open(txt_path, 'r')
    data = []
    for line in f:
        data.append(line.strip())
    print(data)
    f.close()

    # lines = str(line).split(' ')
    # box_num = len(data)
    pic_name = txt_name_path.replace(".txt", ".jpg")

    node_root = Element('annotation')
    node_folder = SubElement(node_root, 'folder')
    node_folder.text = 'JPEGImages'
    node_filename = SubElement(node_root, 'filename')
    # 图片名字
    node_filename.text = pic_name
    # 图像尺寸
    node_size = SubElement(node_root, 'size')
    node_width = SubElement(node_size, 'width')
    node_width.text = str(shape[1])

    node_height = SubElement(node_size, 'height')
    node_height.text = str(shape[0])

    node_depth = SubElement(node_size, 'depth')
    node_depth.text = str(shape[2])
    # 第二层循环遍历有多少个框
    for dat in data:
        dat = dat.split(" ")
        print(len(dat))
        print(dat)
        # 分支把标签合并
        if len(dat) == 5:
            Label = dat[0]

            Xmin = math.floor(float(dat[1]))
            Ymin = math.floor(float(dat[2]))
            Xmax = math.ceil(float(dat[3]))
            Ymax = math.ceil(float(dat[4]))

            # Xmin = int(float(dat[1]))
            # Ymin = int(float(dat[2]))
            # Xmax = int(float(dat[3]))
            # Ymax = int(float(dat[4]))
            print(Label, Xmin, Ymin, Xmax, Ymax)
            # img = cv2.rectangle(img, (Xmin, Ymin), (Xmax, Ymax), (0, 255, 0), 1)

            cls_name = Label

            node_object = SubElement(node_root, 'object')
            node_name = SubElement(node_object, 'name')
            # 类别名字
            node_name.text = cls_name

            node_bndbox = SubElement(node_object, 'bndbox')
            node_xmin = SubElement(node_bndbox, 'xmin')
            node_xmin.text = str(Xmin)
            node_ymin = SubElement(node_bndbox, 'ymin')
            node_ymin.text = str(Ymin)
            node_xmax = SubElement(node_bndbox, 'xmax')
            node_xmax.text = str(Xmax)
            node_ymax = SubElement(node_bndbox, 'ymax')
            node_ymax.text = str(Ymax)

        else:
            Label = dat[0] + dat[1]

            Xmin = math.floor(float(dat[2]))
            Ymin = math.floor(float(dat[3]))
            Xmax = math.ceil(float(dat[4]))
            Ymax = math.ceil(float(dat[5]))

            # Xmin = int(float(dat[2]))
            # Ymin = int(float(dat[3]))
            # Xmax = int(float(dat[4]))
            # Ymax = int(float(dat[5]))
            print(Label, Xmin, Ymin, Xmax, Ymax)
            # img = cv2.rectangle(img, (Xmin, Ymin), (Xmax, Ymax), (0, 255, 0), 1)

            cls_name = Label

            node_object = SubElement(node_root, 'object')
            node_name = SubElement(node_object, 'name')
            # 类别名字
            node_name.text = cls_name
            node_difficult = SubElement(node_object, 'difficult')
            node_difficult.text = '0'

            node_bndbox = SubElement(node_object, 'bndbox')
            node_xmin = SubElement(node_bndbox, 'xmin')
            node_xmin.text = str(Xmin)
            node_ymin = SubElement(node_bndbox, 'ymin')
            node_ymin.text = str(Ymin)
            node_xmax = SubElement(node_bndbox, 'xmax')
            node_xmax.text = str(Xmax)
            node_ymax = SubElement(node_bndbox, 'ymax')
            node_ymax.text = str(Ymax)
    xml = tostring(node_root, pretty_print=True)
    dom = parseString(xml)
    # print xml 打印查看结果
    xml_name = pic_name.replace(".jpg", "")
    xml_name = os.path.join(save_xml_path, xml_name + '.xml')
    with open(xml_name, 'wb') as f:
        # f.write(dom.toprettyxml(indent='\t', encoding='utf-8'))
        f.write(xml)


def make_voc_dir():
    os.makedirs('VOC2007/Annotations')
    os.makedirs('VOC2007/ImageSets')
    os.makedirs('VOC2007/ImageSets/Main')
    os.makedirs('VOC2007/ImageSets/Layout')
    os.makedirs('VOC2007/ImageSets/Segmentation')
    os.makedirs('VOC2007/JPEGImages')
    os.makedirs('VOC2007/SegmentationClass')
    os.makedirs('VOC2007/SegmentationObject')


if __name__ == '__main__':
    dataset_folder = ["train", "validation", "test"]
    class_folder = ["15instruments"]
    root_path = "E:/study/OIDv4_ToolKit/OID/Dataset/"
    make_voc_dir()
    # 遍历train,val,test数据集
    for folder1 in dataset_folder:
        # ../OID/UnRestraint_Of_MarineCreature_In_OpenImagev4/Dataset/train/
        dataset_root_path = root_path + folder1 + "/"
        # 遍历具体类别
        for folder2 in class_folder:
            # ../OID/UnRestraint_Of_MarineCreature_In_OpenImagev4/Dataset/train/Seahorse/
            label_root_path = dataset_root_path + folder2 + "/"

            save_xml_path = 'VOC2007/Annotations'

            # ../OID/UnRestraint_Of_MarineCreature_In_OpenImagev4/Dataset/train/Seahorse/Label/
            files = os.listdir(label_root_path + "/Label/")
            print(files)
            # 遍历label和box的标签文件
            for file in files:
                # 对于每一个label.txt:
                # param1:../OID/UnRestraint_Of_MarineCreature_In_OpenImagev4/Dataset/train/Seahorse/
                # param2:imglabel.txt
                # param3:annotation
                make_xml(label_root_path, file, save_xml_path)

改完之后生成了相关文件夹和Annotation文件,图片也都复制到了JPEGImages

 annotation和image的命名仍为当时的图片命名,但是看见很多文章都写命名有要求,最好是五位数 6位数,于是用下面的代码改了文件名称(注意是6位不是5位,不知道是哪里看到的5位数了!)

import os
import glob

# folder_path = r'E:\study\OIDv4_ToolKit\OID\Dataset\VOC2007\JPEGImages'
folder_path = 'E:\study\OIDv4_ToolKit\OID\Dataset\VOC2007\Annotation'
num = 1

if __name__ == '__main__':

    for file in glob.glob(os.path.join(folder_path, "*.xml")):
        s = '%05d' % num  # 前面补零占位
        os.rename(os.path.join(folder_path, file), os.path.join(folder_path, str(s) + '.xml'))
        num += 1

但是annotation中的xml文件还有图片名信息,于是又用下面的代码修改了xml文件里filename内容

参考:Python修改xml文件内容_python 修改xml内容_pika虫的博客-CSDN博客

import xml.etree.ElementTree as ET
import os
 
 
# 批量修改整个文件夹所有的xml文件
def change_all_xml(xml_path):
    filelist = os.listdir(xml_path)
    print(filelist)
    # 打开xml文档
    for xmlfile in filelist:
        xmlpath = os.path.join(xml_path, xmlfile)
        doc = ET.parse(xmlpath)
        root = doc.getroot()
        sub1 = root.find('filename')  # 找到filename标签,
        sub1.text = xmlfile  # 修改标签内容
 
        doc.write(xmlpath)  # 保存修改
 
 
# 修改某个特定的xml文件
def change_one_xml(xml_path):          # 输入的是这个xml文件的全路径
    # 打开xml文档
    doc = ET.parse(xml_path)
    root = doc.getroot()
    sub1 = root.find('filename')       # 找到filename标签,
    sub1.text = '07_205.jpg'           # 修改标签内容
    doc.write(xml_path)  # 保存修改
    print('----------done--------')
 
 
change_all_xml(r'E:\study\OIDv4_ToolKit\OID\Dataset\VOC2007\Annotations')     # xml文件总路径
# xml_path = r'Z:\pycharm_projects\ssd\VOC2007\Annotations\07_205.xml'
# change_one_xml(xml_path)

接下来创建和添加main文件夹下的文件

import os
import random
 
trainval_percent = 0.9
train_percent = 0.8
xmlfilepath = 'E:/study/OIDv4_ToolKit/OID/Dataset/VOC2007/Annotations'
txtsavepath = 'E:/study/OIDv4_ToolKit/OID/Dataset/VOC2007/ImageSets/Main'
total_xml = os.listdir(xmlfilepath)
 
num=len(total_xml)
list=range(num)
tv=int(num*trainval_percent)
tr=int(tv*train_percent)
trainval= random.sample(list,tv)
train=random.sample(trainval,tr)
 
ftrainval = open(txtsavepath+'/trainval.txt', 'w')
ftest = open(txtsavepath+'/test.txt', 'w')
ftrain = open(txtsavepath+'/train.txt', 'w')
fval = open(txtsavepath+'/val.txt', 'w')
 
for i  in list:
    name=total_xml[i][:-4]+'\n'
    if i in trainval:
        ftrainval.write(name)
        if i in train:
            ftrain.write(name)
        else:
            fval.write(name)
    else:
        ftest.write(name)
 
ftrainval.close()
ftrain.close()
fval.close()
ftest .close()

发现object需要为小写,但是Open Image的类别为首字母大写,需要修改,否则可能出现KeyError,使用以下代码修改(记得同步修改pacal_voc.py中的类别名为小写)

参考:Python修改xml文件中的类别名_Soochow_NJU_Smile的博客-CSDN博客

#修改xml文件中的目标的名字
import os, sys
import glob
from xml.etree import ElementTree as ET

# 批量读取Annotations下的xml文件
# per=ET.parse(r'C:\Users\xxxxx\Desktop\Annotations\000003.xml')
xml_dir = r'E:\study\OIDv4_ToolKit\OID\Dataset\VOC2007\Annotations'
xml_list = glob.glob(xml_dir + '/*.xml')
for xml in xml_list:
    print(xml)
    per = ET.parse(xml)
    p = per.findall('/object')

    for oneper in p:  # 找出person节点
        child = oneper.getchildren()[0]  # 找出person节点的子节点
        child.text = child.text.lower()
        # if child.text == 'yanwu':   #需要修改的名字
        #     child.text = 'smoke'    #修改成什么名字

    per.write(xml)
    print(child.tag, ':', child.text)

猜你喜欢

转载自blog.csdn.net/ZZZZ_Y_/article/details/129572133