VOC类型的xml标签在训练前的清洗工作

标注工具

labelimg

数据清洗

在收集好所有图片以及对应的标签后,需要对数据进行清洗工作。包括剔除没有标签的图片,剔除没有图片的标签,统计数据中的标签名以及数量,重命名打错字的标签,合并标签,标签替换等等。
在这里插入图片描述

1. 统计数据中标签名

有时,可能出现标错标签名的情况,如有些 ‘peroson’ 的标签名打错了,写成了 ‘people’,或者同一类别中,有的写了下划线,有的使用空格表示,例如 ‘cargo_house’ 和 ‘cargo house’ 。统计出所有标签名以及类别数后,我们能够很方便的将错误找出来。

import os
import xml.dom.minidom

xml_path = '/home/jim/Desktop/合并/VOCdir/xml'
xmls = os.listdir(xml_path)
rate = {} # 创建一个字典用于存放标签名和对应的出现次数

for xml_file in xmls:
    if xml_file.endswith('.xml'):
        fullname = os.path.join(xml_path,xml_file)
        dom = xml.dom.minidom.parse(fullname) # 打开XML文件
        collection = dom.documentElement # 获取元素对象
        objectlist = collection.getElementsByTagName('object') # 获取标签名为object的信息
        for object in objectlist:
            namelist = object.getElementsByTagName('name') # 获取子标签name的信息
            objectname = namelist[0].childNodes[0].data # 取到name具体的值
            if objectname not in rate: # 判断字典里有没有标签,如无添加相应字段
                rate[objectname] = 0
            rate[objectname] += 1

print(rate)
# 画图
rate = sorted(rate.items(), key=lambda x: x[1],reverse = True)
import matplotlib.pyplot as plt
object = []
number = []
for key in rate:
    object.append(key[0])
    number.append(key[1])
plt.figure()
plt.bar(object, number)
plt.title('result')
plt.show()

输出为:

{‘yes’: 2837, ‘person’: 10107, ‘cargo_house’: 3264, ‘crane boom’: 339, ‘console’: 4732, ‘no’: 2126, ‘excavator arm’: 2206, ‘hook arm’: 1500}
在这里插入图片描述

2. 批量重命名

如果存在类似于 ‘people’ 和 ‘person’ 这种标签名错误的情况,可以通过以下代码批量重命名。

import os  
import os.path
from xml.etree.ElementTree import parse, Element

def changeName(xml_fold, origin_name, new_name):
   files = os.listdir(xml_fold)
   cnt = 0
   for xmlFile in files:
      if xmlFile.endswith('.xml'):
         file_path = os.path.join(xml_fold, xmlFile)
         dom = parse(file_path)
         root = dom.getroot()
         for obj in root.iter('object'):#获取object节点中的name子节点
            tmp_name = obj.find('name').text
            if tmp_name == origin_name: # 修改
               obj.find('name').text = new_name
               print("change %s to %s." % (origin_name, new_name))
               cnt += 1
         dom.write(file_path,encoding='utf-8')#保存到指定文件
   print("有%d个文件被成功修改。" % cnt)

changeName('/home/jim/Desktop/合并/VOCdir/xml/','people','peroson')

3. 合并xml

对于某个文件夹下的所有图片,使用labelimg进行标注,获得voc类型的xml格式的标签。由于在进行标注工作时,将不同的类别分开标注了,得到标签文件夹有两个,第一个文件夹存储了类别 a 和类别 b 的 labels ,第二个文件夹存储了类别 c, d, e… 的 labels 。现在想要将相同图片的标签进行,即原本一张图片可能有两个对应的 xml,现在要使得一张图片只有一个对应的 xml。之前的博客有详细介绍:合并使用labelimg标注的同一张图片的两个不同xml标签

4. 标签替换

类似于3,同样对于某个文件夹下的所有图片,第一个文件夹存储了类别 a, b, c, d 的 labels,第二个文件夹存储了d的labels,发现第二个文件夹的d标签标注的更好,要将第一个文件夹下的d替换。

from xml.etree.ElementTree import ElementTree, Element, parse
import xml.etree.ElementTree as ET
import os
import shutil

# 以person类别为例,d表示person
old_path = 'a,b,c,d的labels路径'
new_xml_path = 'd类别标注的更好的xml路径'
out_path = '输出路径'

# 格式化
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

ori = 0
wen = 0
for file in os.listdir(old_path):
    if file.endswith('.xml'):
        # 找到同名的xml
        if os.path.exists(os.path.join(new_xml_path, file)):
            print('fusing',file)
            # 原始标签
            tree_ori = parse(os.path.join(old_path, file))
            root_ori = tree_ori.getroot()  # annotation

            # 更好的person标签
            tree_img = parse(os.path.join(new_xml_path,file))
            root_img = tree_img.getroot()  # annotation

            # 找到差标签中所有的object
            object_out = tree_ori.findall('object')
            # print(object_person)
            object_person_name = []

            # 删除差xml中的person
            for i in range(len(object_out)):
                for leaf in list(object_out[i]):
                    if leaf.tag == 'name' and leaf.text == 'person':
                        root_ori.remove(object_out[i])

            # 找到更好标签中所有的object
            object_wen = tree_img.findall('object')
            # 将更好标签中的person加入到差xml中
            for i in range(len(object_wen)):
                for leaf in list(object_wen[i]):
                    if leaf.tag == 'name' and leaf.text == 'person':
                        root_ori.append(object_wen[i])
                        __indent(root_ori)
            tree_ori.write(os.path.join(out_path, file))
        else:
            # 将不同名的直接复制
            print(file)
            shutil.copy(os.path.join(old_path,file),os.path.join(out_path, file))

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值