待解决问题
对于某个文件夹下的所有图片,使用labelimg进行标注,获得voc类型的xml格式的标签。由于在进行标注工作时,将不同的类别分开标注了,得到标签文件夹有两个,第一个文件夹存储了类别 a 和类别 b 的 labels ,第二个文件夹存储了类别 c, d, e… 的 labels 。现在想要将相同图片的标签进行,即原本一张图片可能有两个对应的 xml,现在要使得一张图片只有一个对应的 xml。
目标效果
原图:
标签1
标签2
标签合并
解决思路
通过分析 xml 文件,得知关键的标签信息存在于 xml 中的 object节点中,那么只要将相同图片的两个 xml 文件中的object进行拼接即可。
解决方案
例如:
xml1:
images
1_191.jpg
/home/shan/Desktop/VOC/images/1_191.jpg
Unknown
1920
1080
3
0
no
Unspecified
0
0
240
37
290
79
no
Unspecified
0
0
401
23
460
65
xml2:
xu
1_191.jpg
/home/aibc/Desktop/xu/1_191.jpg
Unknown
1920
1080
3
0
excavator arm
Unspecified
0
0
938
38
1063
116
person
Unspecified
1
0
1037
1
1047
28
xml1 和 xml2 都是 图片1_191.jpg 的标签,我们现在将它们合并。
先了解一些 xml 基本操作
读取
读取文档:tree = ET.parse()
获得根节点:root = tree.getroot()
获得所有子节点:list()
查找子节点,注意这里不会递归查找所有子节点:root.findall('object')
查找子节点,递归查找所有子节点:root.iter()
查看节点名称:root.tag
写入
创建节点:root = ET.Element)
创建文档:tree = ET.ElementTree()
设置文本值:element.text
设置属性:element.set()
添加节点:root.append()
写入文档:tree.write()
代码奉上
单张图片
from xml.etree.ElementTree import ElementTree, Element, parse
import xml.etree.ElementTree as ET
# 缩进对齐
def __indent(elem, level=0):
i = "\n" + level*"\t"
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + "\t"
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
__indent(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
# 读取xml1文件
# 为了方便演示,我将两个 1_191.xml 分别手动重命名为 1_191_1.xml 和 1_191_2.xml
tree_1 = parse('1_191_1.xml')
root_1 = tree_1.getroot() # annotation
new_1 = tree_1
# 读取xml2文件
tree_2 = parse('1_191_2.xml')
root_2 = tree_2.getroot() # annotation
# 找到所有object节点
object = (tree_2.findall('object'))
length = len(object)
# 将tree_2中的所有object节点加入到root_1中
for i in range(length):
root_1.append(object[i])
__indent(root_1)
new_1.write('./1_191.xml')
得到的输出结果为:
images
1_191.jpg
/home/shan/Desktop/VOC/images/1_191.jpg
Unknown
1920
1080
3
0
no
Unspecified
0
0
240
37
290
79
no
Unspecified
0
0
401
23
460
65
excavator arm
Unspecified
0
0
938
38
1063
116
person
Unspecified
1
0
1037
1
1047
28
可以看到,问题解决_
批量操作
from xml.etree.ElementTree import ElementTree, Element, parse
import xml.etree.ElementTree as ET
import os
import shutil
hole_path = './Annotations'
arm_path = './Anno'
out_path = './Fusing'
# 格式化
def __indent(elem, level=0):
i = "\n" + level*"\t"
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + "\t"
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
__indent(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
for hole_xml in os.listdir(hole_path):
# 将同名xml合并
if os.path.exists(os.path.join(arm_path,hole_xml)):
print('fusing',hole_xml)
tree_hole = parse(os.path.join(hole_path,hole_xml))
root_hole = tree_hole.getroot() # annotation
new_hole = tree_hole
tree_arm = parse(os.path.join(arm_path,hole_xml))
root_arm = tree_arm.getroot() # annotation
object = (tree_arm.findall('object'))
for i in range(len(object)):
root_hole.append(object[i])
__indent(root_hole)
new_hole.write(os.path.join(out_path,hole_xml))
# 不同名xml复制
else:
print('copying',hole_xml)
shutil.copy(os.path.join(hole_path,hole_xml), out_path)
# 将不同名xml复制
for arm_xml in os.listdir(arm_path):
if not os.path.exists(os.path.join(out_path,arm_xml)):
print('copying')
shutil.copy(os.path.join(arm_path, arm_xml), out_path)
参考链接:
原文链接:https://blog.csdn.net/weixin_41735859/article/details/107072533