[MBJC] (labelimg) txt to xml, xml to txt, txt to modify label name, xml to modify label name, python script (VOC-yolo) [001]

xml_txt_mutual_conversion

VOC Yolo tag modification conversion script

Github:

链接: https://github.com/Samsara0Null/xml_txt_mutual_conversion

CSDN home page:

链接: https://blog.csdn.net/noneNull0?type=blog

Bilibili video demonstration explanation:

Link: https://www.bilibili.com/video/BV1ie4y1D77dvd_source=a6067b731745325c01a4edfa46bf5a04

umm, the comment area pointed out that when using txt_xml.py, if the label is of character type, a value error similar to ValueError: could not convert string 'A' to float64 at row 0, column 1.
Que has a point. He simply modified it. As a supplement, the usage is the same as before. If you modify the path, it should be able to be used directly. If you have relevant needs, you can try it

Connection: https://wwin.lanzoue.com/i12Yt0pj83fg

Here are some scripts to help convert txt and xml format tag file formats and modify tag names (applicable to tags in VOC-yolo project format)

You may need to install some dependencies and configure the environment (just follow the MoudleNotFound error report)

My environment:

  • VSCode+Anaconda
  • python==3.6.13
  • pillow==8.3.1
  • opencv-python==4.6.0.66
  • numpy==1.19.5
  • lxml==3.8.0

Demo sample:

Insert image description here
Insert image description here

txt_change_label.py

# 项目名称:DI_QueXianShiJueJianCe
# 程序内容:修改txt标签名称
# 作   者:MBJC
# 开发时间:2022/7/26 11:10

import os
import re
# 路径
path = './txt/'
# 文件列表
files = []
for file in os.listdir(path):
    if file.endswith(".txt"):
        files.append(path+file)
# 逐文件读取-修改-重写
for file in files:
    with open(file, 'r') as f:
        new_data = re.sub('^0', 'car', f.read(), flags=re.MULTILINE)  # 将列中的0替换为car
    with open(file, 'w') as f:
        f.write(new_data)
    with open(file, 'r') as f:
        new_data = re.sub('^1', 'horse', f.read(), flags=re.MULTILINE)  # 将列中的1替换为horse
    with open(file, 'w') as f:
        f.write(new_data)
    with open(file, 'r') as f:
        new_data = re.sub('^2', 'chair', f.read(), flags=re.MULTILINE)  # 将列中的2替换为chair
    with open(file, 'w') as f:
        f.write(new_data)
    with open(file, 'r') as f:
        new_data = re.sub('^3', 'bicycle', f.read(), flags=re.MULTILINE)  # 将列中的3替换为bicycle
    with open(file, 'w') as f:
        f.write(new_data)
  • Code function: Modify txt tag name
  • 1. Modify the folder path where the txt tag file is stored
    The path relative to the script is used here

Insert image description here

  • 2. Modify the desired pre-modification and post-modification tag names according to the gourd picture.

Insert image description here

  • 3. Run txt_change_label.py

Insert image description here

  • 4. Result display

Before running:

Insert image description here

After running:

Insert image description here

txt_xml.py

# 项目名称:xml_txt_mutual_conversion
# 程序内容:jpg,txt转换xml
# 作   者:MBJC
# 开发时间:2022/8/1 9:59

import time
import os
from PIL import Image
import cv2
import numpy as np

'''人为构造xml文件的格式'''
out0 = '''<annotation>
    <folder>%(folder)s</folder>
    <filename>%(name)s</filename>
    <path>%(path)s</path>
    <source>
        <database>None</database>
    </source>
    <size>
        <width>%(width)d</width>
        <height>%(height)d</height>
        <depth>3</depth>
    </size>
    <segmented>0</segmented>
'''
out1 = '''    <object>
        <name>%(class)s</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <difficult>0</difficult>
        <bndbox>
            <xmin>%(xmin)d</xmin>
            <ymin>%(ymin)d</ymin>
            <xmax>%(xmax)d</xmax>
            <ymax>%(ymax)d</ymax>
        </bndbox>
    </object>
'''

out2 = '''</annotation>
'''

'''txt转xml函数'''


def translate(fdir, lists):
    source = {
    
    }
    label = {
    
    }
    for jpg in lists:
        print(jpg)
        if jpg[-4:] == '.jpg':
            image = cv2.imread(jpg)  # 路径不能有中文
            h, w, _ = image.shape  # 图片大小
            #            cv2.imshow('1',image)
            #            cv2.waitKey(1000)
            #            cv2.destroyAllWindows()

            fxml = jpg.replace('.jpg', '.xml')
            fxml = open(fxml, 'w')
            imgfile = jpg.split('/')[-1]
            source['name'] = imgfile
            source['path'] = jpg
            source['folder'] = os.path.basename(fdir)

            source['width'] = w
            source['height'] = h

            fxml.write(out0 % source)
            txt = jpg.replace('.jpg', '.txt')

            lines = np.loadtxt(txt)  # 读入txt存为数组
            # print(type(lines))

            for box in lines:
                # print(box.shape)
                if box.shape != (5,):
                    box = lines

                '''把txt上的第一列(类别)转成xml上的类别
                   我这里是labelimg标123,对应txt上面的012'''
                label['class'] = str(int(box[0]) + 1)  # 类别索引从1开始

                '''把txt上的数字(归一化)转成xml上框的坐标'''
                xmin = float(box[1] - 0.5 * box[3]) * w
                ymin = float(box[2] - 0.5 * box[4]) * h
                xmax = float(xmin + box[3] * w)
                ymax = float(ymin + box[4] * h)

                label['xmin'] = xmin
                label['ymin'] = ymin
                label['xmax'] = xmax
                label['ymax'] = ymax

                # if label['xmin']>=w or label['ymin']>=h or label['xmax']>=w or label['ymax']>=h:
                #     continue
                # if label['xmin']<0 or label['ymin']<0 or label['xmax']<0 or label['ymax']<0:
                #     continue

                fxml.write(out1 % label)
            fxml.write(out2)


if __name__ == '__main__':
    file_dir = 'E:/CSDN/xml_txt_mutual_conversion/jpg_txt' #修改目标文件夹路径
    lists = []
    for i in os.listdir(file_dir):
        if i[-3:] == 'jpg':
            lists.append(file_dir + '/' + i)
            # print(lists)
    translate(file_dir, lists)
    print('---------------Done!!!--------------')
  • Code function: txt tag format and corresponding jpg image conversion to xml tag format
  • 1. Put the txt and corresponding jpg in the same folder

Insert image description here

  • 2. Modify the target folder path

Insert image description here

  • 3. Run txt_xml.py

Insert image description here

  • 4. Result display

Before running:

Insert image description here

After running:

Insert image description here

Can be opened in labelimg (note that label 0 in txt will become label 1 in xml)

Insert image description here

Insert image description here

Search xml in the folder to get the file

Insert image description here

xml_change_label.py

# 项目名称:DI_QueXianShiJueJianCe
# 程序内容:修改xml标签名
# 作   者:MBJC
# 开发时间:2022/7/10 8:30

"""
批量修改xml文件中的缺陷类别名称
当有多个物体时,多个物体的名称均能被修改
"""

from lxml.etree import Element, SubElement, tostring, ElementTree
from xml.dom import minidom
import xml.etree.ElementTree as ET
import os
# 修改自己的路径
template_file = r'E:\CSDN\xml_txt_mutual_conversion\xml'  #这里是存放xml文件的文件夹
xmllist = os.listdir(template_file)
for xml in xmllist:
    #print(xml)
    tree = ET.parse(os.path.join(template_file,xml))
    root = tree.getroot() # 获取根节点
    for child in root:
        print(child.tag,child.attrib)
        if child.tag == 'object':
            name=child.find('name').text
            # print(name)
            if name == '1':
                child.find('name').text = 'car'
                tree=ET.ElementTree(root)
            elif name == '2':
                child.find('name').text = 'horse'
                tree = ET.ElementTree(root)
            elif name == '3':
                child.find('name').text = 'chair'
                tree = ET.ElementTree(root)
            elif name == '4':
                child.find('name').text = 'bicycle'
                tree = ET.ElementTree(root)
    tree.write(os.path.join(template_file,xml))

  • Code function: Modify xml tag name
  • 1. Modify the folder path where the xml tag file is stored

Insert image description here

  • 2. Modify the tags you want to modify, for example: 1->car. If the number of tags is different, just delete or add elif statements.

Insert image description here

  • 3. Run xml_change_label.py

Insert image description here

  • 4. Result display

Before running:

Insert image description here

After running:

Insert image description here

xml_txt.py

# 项目名称:xml_txt_mutual_conversion
# 程序内容:xml转txt
# 作   者:MBJC
# 开发时间:2022/8/1 11:29

import xml.etree.ElementTree as ET
import os
from os import getcwd
import glob

# 1.
# 自己创建文件夹,例如:label_mal label_txt  也可以修改别的
image_set = 'xml'  # 需要转换的文件夹名称(文件夹内放xml标签文件)
imageset2 = 'txt'  # 保存txt的文件夹
# 2.
# 换成你的类别 当前的顺序,就txt 0,1,2,3 四个类别
classes = ['car', 'horse', 'chair', 'bicycle']  # 标注时的标签 注意顺序一定不要错。

# 3.
# # 转换文件夹的绝对路径
# data_dir = 'D:/detectAuto_/data'
# 或者 读取当前路径
data_dir = getcwd()  # 当前路径


'''
xml中框的左上角坐标和右下角坐标(x1,y1,x2,y2)
》》txt中的中心点坐标和宽和高(x,y,w,h),并且归一化
'''


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(data_dir, imageset1, imageset2, image_id):
    in_file = open(data_dir + '/%s/%s.xml' % (imageset1, image_id))  # 读取xml
    out_file = open(data_dir + '/%s/%s.txt' % (imageset2, image_id), 'w')  # 保存txt

    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('%.6f' % a) for a in bb]) + '\n')


image_ids = []
for x in glob.glob(data_dir + '/%s' % image_set + '/*.xml'):
    image_ids.append(os.path.basename(x)[:-4])
print('\n%s数量:' % image_set, len(image_ids))  # 确认数量
i = 0
for image_id in image_ids:
    i = i + 1
    convert_annotation(data_dir, image_set, imageset2, image_id)
    print("%s 数据:%s/%s文件完成!" % (image_set, i, len(image_ids)))

print("Done!!!")
  • Code function: convert xml tag format to txt tag format

  • 1. Modify the path of the xml folder to be modified and the target txt folder

[External link image transfer failed, the source site may have anti-theft inserted here! Link mechanism, recommended description] It is recommended to upload the image to https://(imblog.csnmg.ci/1ngx5f06aa398049420a868e0b560d21fda.png2(https://ig-blog .csdnimg.cn/5f06aa398049420a868e0b5620d21fda.png)]

Warm reminder: Note that if the current path is read, the first two paths must be modified into relative paths.

Insert image description here

  • 2. Replace the name sequence with the desired order of the XML tag names to be converted.

Insert image description here

  • 3. Run xml_txt.py

Insert image description here

4. Result display

Before running:

Insert image description here

After running:

Insert image description here

Author: MBJC
Last modification time: 2022/8/2 19:48

Guess you like

Origin blog.csdn.net/noneNull0/article/details/126134587