目标检测中将xml标签转换为txt(voc格式转换为yolo)

目标检测中将xml标签转换为txt(voc格式转换为yolo)

xml格式:
".xml"格式是可扩展标记语言,因其可以跨越多平台的属性,成为网络数据传输的重要工具。如下图所示,xml格式数据特点就是简单易理解,清晰易操控。我们可以清晰的看到这个数据的文件夹,文件名,路径,来源,格式,目标对象的类别,位置等信息。
目标检测中将xml标签转换为txt(voc格式转换为yolo)_第1张图片
txt格式:
      “.txt”格式就是最常见的文本类型,这种格式保存的内容简单,占用的内存小。如下图所示,为用notebook打开的一个目标检测数据的类别标签,它有两个目标物体,一行代表一个,类别标签后的四个浮点数代表目标的中心位置x,y和长宽w,h(以一副图片左上角为原点的相对位置)。因txt为保存的目标检测数据没有类别名称,所以通常会在一系列类别文件后,有一个classes.txt,用来保存类名称。
txt格式数据举例
xml格式转换为txt:
      通常的voc数据集会有三个文件,一个是JPEGImages,用来保存原始图像;第二个是Annotations,用来保存标签信息,它一般与JPEGImages中的图像一一对应,即JPEGImages中每幅图像在Annotations中有与它一一对应的xml文件;第三个是ImageSets,它包含一个Main的子文件夹,Main中含有至少三个txt文件,分别为train.txt,test.txt,val.txt,记录训练、测试、验证集的图像序号。在接下来的代码中我们分别生成三个文件夹,用来保存训练、测试、验证的txt标签。
      xml格式记录的信息多,转向txt也较为简单,只用把相应的信息进行提取即可。
      首先导包,都是很简单的包,一般下载编译器自带的。

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

      然后获取全部的类别标签,因为xml的类别信息保存在每个xml文件中,没有一起的类别展示。而用于yolo的txt需要一个完整的类别文件描述。

# 获取全部类别标签
#image_id是每个xml的名称
classes = []
def gen_classes(image_id):

    in_file = open('%s/Annotations/%s.xml'%(path,image_id))
    tree = ET.parse(in_file)
    root = tree.getroot()
    
    for obj in root.iter('object'):
        cls_name = obj.find('name').text
        if cls_name in classes:
            pass
        else:
            classes.append(cls_name)
    return classes

      将实际位置坐标转换为相对位置坐标的代码,其中size是图片大小,box是目标物品的位置。

#改变坐标格式
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)

      读取xml文件中内容并将转换好的信息写入txt文件

#这里是读取xml文件中内容并将转换好的信息写入txt文件的过程,
#主要就是索引前面classes中的名字将名字转换成编号再写入txt
#image_set是train、test、val中的一个
def convert_annotation(image_set,image_id):
    in_file = open('%s/Annotations/%s.xml'%(path,image_id))
    out_file = open('%s/%s'%(path,image_set)+'labels/%s.txt'%image_id, 'w')
    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'):
        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))
        bb = convert((w,h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')

      调用以上函数,进行实际操作。其中path是文件的路径,sets是需要进行格式转变的文件,一般包括训练集,测试集,验证集。

#路径是文件路径,该路径下应该至少包含三个文件夹:JPEGImages、Annotations、ImageSets
path = 'C:/Users/zy080/Downloads/水面漂浮物数据集-2400/VOCdevkit/VOC2007'
sets = ['train','test','val']

for image_set in sets:
    if not os.path.exists('%s/%s'%(path,image_set)+'labels/'):
        os.makedirs('%s/%s'%(path,image_set)+'labels/')
    image_ids = open('%s/ImageSets/Main/%s.txt'%(path,image_set)).read().strip().split()
    for image_id in image_ids:
        gen_classes(image_id)
        convert_annotation(image_set,image_id)
    classes_file = open('%s/%s'%(path,image_set)+'labels/classes.txt','w')
    classes_file.write("\n".join([a for a in classes]))
    classes_file.close()

总的代码如下:

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

# 获取全部类别标签
classes = []
def gen_classes(image_id):
    in_file = open('%s/Annotations/%s.xml'%(path,image_id))
    tree = ET.parse(in_file)
    root = tree.getroot()    
    for obj in root.iter('object'):
        cls_name = obj.find('name').text
        if cls_name in classes:
            pass
        else:
            classes.append(cls_name)
    return classes

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_set,image_id):
    in_file = open('%s/Annotations/%s.xml'%(path,image_id))
    out_file = open('%s/%s'%(path,image_set)+'labels/%s.txt'%image_id, 'w')
    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'):
        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))
        bb = convert((w,h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')

path = 'C:/Users/zy080/Downloads/水面漂浮物数据集-2400/VOCdevkit/VOC2007'
sets = ['train','test','val']
for image_set in sets:
    if not os.path.exists('%s/%s'%(path,image_set)+'labels/'):
        os.makedirs('%s/%s'%(path,image_set)+'labels/')
    image_ids = open('%s/ImageSets/Main/%s.txt'%(path,image_set)).read().strip().split()
    for image_id in image_ids:
        gen_classes(image_id)
        convert_annotation(image_set,image_id)
    classes_file = open('%s/%s'%(path,image_set)+'labels/classes.txt','w')
    classes_file.write("\n".join([a for a in classes]))
    classes_file.close()

你可能感兴趣的:(深度学习,python,机器学习)