在深度学习目标检测的所用到的数据集中,常会遇到xml格式的标注文件(例如VOC格式的数据集采用的标注文件就是xml格式的)。在我们自己建立xml标注文件或者是将其他类型的标注文件(例如txt、json)转化到xml格式时,就需要了解这方面的知识。
下面我将列出用python借助lxml来进行xml类型文件的创建、添加、修改功能的实现代码。
1.创建xml格式的标注文件
下面展示创建xml格式文件的代码及运行代码后生成的xml文件的内容效果图,这里我们先简单创立一个xml文件,设定根节点、为根节点添加几个子节点、并给节点起名、设定节点包含的文本text信息。
代码如下:
from lxml.etree import Element, tostring, parse
from lxml.etree import SubElement as subElement
def xml_construct(save_path,folder,filename,path,width=800,height=600,depth = 3,segmented=0):
default_text = 'default'
node_root = Element('annotation') # 根节点
node_folder = subElement(node_root, 'folder') # 在节点下添加名为'folder'的子节点
node_folder.text = folder # 设定节点的文字
node_filename = subElement(node_root, 'filename')
node_filename.text = filename
node_path = subElement(node_root, 'path')
node_path.text = path
node_size = subElement(node_root, 'size')
node_size_width = subElement(node_size, 'width')
node_size_width.text = '%s' % int(width)
node_size_height = subElement(node_size, 'height')
node_size_height.text = '%s' % int(height)
node_size_depth = subElement(node_size, 'depth')
node_size_depth.text = '%s' % int(depth)
node_segmented = subElement(node_root, 'segmented')
node_segmented.text = '%s' % int(segmented)
xml = tostring(node_root, pretty_print=True) #将上面设定的一串节点信息导出
with open(save_path,'wb') as f: #将节点信息写入到文件路径save_path中
f.write(xml)
return
#----------调用上面所写的函数进行试验,创建名为test.xml的xml文件----------
xml_construct('test.xml','test','test','test',width=1600,height=1200,)
运行以上代码结果为:
2.为已存在的xml文件进行添加节点
在这里我们展示如何对已存在的xml文件进行添加节点操作,我们接着在上一步骤中生成的test.xml上面来进行修改。
代码如下:
from lxml.etree import Element, tostring, parse
from lxml.etree import SubElement as subElement
def xml_add_object(xml_path,name,id,xmin,ymin,xmax,ymax,pose = 'Unspecified',truncated=0,difficult=0):
tree = parse(xml_path) # 读取xml文件
node_root = tree.getroot() # 找到xml文件的根节点
node_object = subElement(node_root, 'object') #在根节点node_root下面添加名为'object'的子节点
node_object_name = subElement(node_object, 'name') #在根节点node_root的子节点object下面继续添加子节点object的子节点'name'
node_object_name.text = name #设定该节点的文本text信息
node_object_id = subElement(node_object, 'id')
node_object_id.text = '%s' % int(id)
node_object_pose = subElement(node_object, 'pose')
node_object_pose.text = pose
node_object_truncated = subElement(node_object, 'truncated')
node_object_truncated.text = '%s' % int(truncated)
node_object_difficult = subElement(node_object, 'difficult')
node_object_difficult.text = '%s' % int(difficult)
# object坐标
node_bndbox = subElement(node_object, 'bndbox')
node_xmin = subElement(node_bndbox, 'xmin')
node_xmin.text = '%s' % int(xmin)
node_ymin = subElement(node_bndbox, 'ymin')
node_ymin.text = '%s' % int(ymin)
node_xmax = subElement(node_bndbox, 'xmax')
node_xmax.text = '%s' % int(xmax)
node_ymax = subElement(node_bndbox, 'ymax')
node_ymax.text = '%s' % int(ymax)
xml = tostring(node_root, pretty_print=True) #将修改后的xml节点信息导出
with open(xml_path,'wb') as f: #将修改后的xml节点信息覆盖掉修改前的
f.write(xml)
return
#----------试验,在test.xml中进行添加节点操作----------
xml_add_object(xml_path='test.xml',name='test_name',id=999,xmin=1,ymin=2,xmax=3,ymax=4,)
运行以上代码后原先的test.xml文件就被添加了相应的子节点,效果如下:
3.修改已存在的xml文件中特定节点的信息
如果我们只想的对xml文件中某些特定节点信息进行修改的话,可以进行一下代码操作(这里我们还是以上面的test.xml文件为操作对象,将其中的size节点下的width和height节点信息进行修改):
from lxml.etree import Element, tostring, parse
from lxml.etree import SubElement as subElement
def modify_size(xml_path,size_width=800,size_height=600):
tree = parse(xml_path)
width = tree.xpath('//width')#这里返回的width是一个包含所有名称中带有"width"的节点的列表
for width_i in width:
width_i.text = '%s' % int(size_width) #这里直接写width_i.text = size_width会报错
height = tree.xpath('//height')
for height_i in height:
height_i.text = '%s' % int(size_height)
node_root = tree.getroot()
xml = tostring(node_root, pretty_print=True)
with open(xml_path,'wb') as f:
f.write(xml)
return
#----------试验----------
#以上面的test.xml文件为操作对象,将其中的size节点下的width和height节点信息进行修改
modify_size('test.xml',size_width=800,size_height=600)
效果如下: