如果你是深度学习的一员,那么平时在训练模型的时候,就会常看到一些标注是使用xml文件来做的,比如常用到的一个数据集VOC,它的Annotations就是用xml来储存图片中对象的属性的。
所以对于熟悉读取xml文件是很有必要的,我们先来看个xml文件,来自VOC2012的对2007_000027.jpg图片里面对象属性的标注,2007_000027.xml:
<annotation>
<folder>VOC2012</folder>
<filename>2007_000027.jpg</filename>
<source>
<database>The VOC2007 Database</database>
<annotation>PASCAL VOC2007</annotation>
<image>flickr</image>
</source>
<size>
<width>486</width>
<height>500</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>person</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>174</xmin>
<ymin>101</ymin>
<xmax>349</xmax>
<ymax>351</ymax>
</bndbox>
<part>
<name>head</name>
<bndbox>
<xmin>169</xmin>
<ymin>104</ymin>
<xmax>209</xmax>
<ymax>146</ymax>
</bndbox>
</part>
<part>
<name>hand</name>
<bndbox>
<xmin>278</xmin>
<ymin>210</ymin>
<xmax>297</xmax>
<ymax>233</ymax>
</bndbox>
</part>
<part>
<name>foot</name>
<bndbox>
<xmin>273</xmin>
<ymin>333</ymin>
<xmax>297</xmax>
<ymax>354</ymax>
</bndbox>
</part>
<part>
<name>foot</name>
<bndbox>
<xmin>319</xmin>
<ymin>307</ymin>
<xmax>340</xmax>
<ymax>326</ymax>
</bndbox>
</part>
</object>
</annotation>
那如何来读取里面的节点与它的内容呢,这里需要使用到xml.etree.ElementTree这样的一个库
import xml.etree.ElementTree as ET
tree=ET.parse('2007_000027.xml')
通过parse解析文件,生成一个树的对象,然后在这个对象里面去寻找节点即可
比如这里,我们想要读取图片的宽和高节点的属性值,也就是节点size里面的width与height,通过tree中的find来查找:
tree.find('size').find('width').text
tree.find('size').find('height').text
注意的是,这里查找出来的486和500的值,是str类型而不是int,所以如果是需要为整型类型时,需要做类型转换
如果是多个同样节点,比如多个<object>节点,如何读取呢?
这里使用findall来进行遍历访问,返回的是列表,也就是find获取的元素的集合,我们来看下多个<object>节点的xml文件2007_000032.xml:
<annotation>
<folder>VOC2012</folder>
<filename>2007_000032.jpg</filename>
<source>
<database>The VOC2007 Database</database>
<annotation>PASCAL VOC2007</annotation>
<image>flickr</image>
</source>
<size>
<width>500</width>
<height>281</height>
<depth>3</depth>
</size>
<segmented>1</segmented>
<object>
<name>aeroplane</name>
<pose>Frontal</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>104</xmin>
<ymin>78</ymin>
<xmax>375</xmax>
<ymax>183</ymax>
</bndbox>
</object>
<object>
<name>aeroplane</name>
<pose>Left</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>133</xmin>
<ymin>88</ymin>
<xmax>197</xmax>
<ymax>123</ymax>
</bndbox>
</object>
<object>
<name>person</name>
<pose>Rear</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>195</xmin>
<ymin>180</ymin>
<xmax>213</xmax>
<ymax>229</ymax>
</bndbox>
</object>
<object>
<name>person</name>
<pose>Rear</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>26</xmin>
<ymin>189</ymin>
<xmax>44</xmax>
<ymax>238</ymax>
</bndbox>
</object>
</annotation>
可以看到有四个<object>分别存储着四个不同的对象,我们来遍历这个节点,顺便将<object>里面的锚框节点<bndbox>的四个属性(左上角和右下角的坐标)也给查找出来,这里我们通过字典保存每个对象方便后期调用,然后将字典都添加到一个列表里面:
tree = ET.parse('2007_000032.xml')
objects = []
for obj in tree.findall('object'):
obj_dict = dict()
obj_dict['name'] = obj.find('name').text
bbox = obj.find('bndbox')
obj_dict['bbox'] = [int(float(bbox.find('xmin').text)), int(float(bbox.find('ymin').text)), int(float(bbox.find('xmax').text)), int(float(bbox.find('ymax').text))]
objects.append(obj_dict)
print(len(objects),objects)
print(objects[3]['bbox'])
'''
4 [{'name': 'aeroplane', 'bbox': [104, 78, 375, 183]}, {'name': 'aeroplane', 'bbox': [133, 88, 197, 123]}, {'name': 'person', 'bbox': [195, 180, 213, 229]}, {'name': 'person', 'bbox': [26, 189, 44, 238]}]
[26, 189, 44, 238]
'''