xml_txt_mutual_conversion
VOC Yolo tag modification conversion script
Github:
链接: https://github.com/Samsara0Null/xml_txt_mutual_conversion
CSDN主页:
链接: https://blog.csdn.net/noneNull0?type=blog
Bilibili视频演示讲解:
链接: https://www.bilibili.com/video/BV1ie4y1D77dvd_source=a6067b731745325c01a4edfa46bf5a04
umm,评论区有提出在使用txt_xml.py时,标签为字符类型,会报类似ValueError: could not convert string ‘A’ to float64 at row 0, column 1.
雀氏有道理,简单修改了一下,作为补充,用法同之前,修改路径,应该可以直接用,有相关需求可以尝试一下
链接: https://wwin.lanzoue.com/i12Yt0pj83fg
这是一些帮助转换txt和xml格式标签文件格式和修改标签名称的脚本(适用于VOC-yolo项目格式的标签)
可能需要安装一些依赖,配置好环境(跟着MoudleNotFound报错走就好了)
我的环境:
- VSCode+Anaconda
- python==3.6.13
- pillow==8.3.1
- opencv-python==4.6.0.66
- numpy==1.19.5
- lxml==3.8.0
演示样本:
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)
- 代码作用:修改txt标签名称
- 1、修改存放txt标签文件的文件夹路径
这里用了相对脚本的路径
- 2、依葫芦画瓢修改想要的修改前和修改后标签名称
- 3、运行 txt_change_label.py
- 4、结果展示
运行前:
运行后:
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标1、2、3,对应txt上面的0、1、2'''
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!!!--------------')
- 代码作用:txt标签格式和对应jpg图片转换xml标签格式
- 1、txt和对应jpg放在同一文件夹内
- 2、修改目标文件夹路径
- 3、运行txt_xml.py
- 4、结果展示
运行前:
运行后:
可在labelimg中打开(注意txt中的标签0会变成xml中的标签1)
在文件夹中搜索xml即可得到文件
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))
- 代码作用:修改xml标签名称
- 1、修改存放xml标签文件的文件夹路径
- 2、修改自己想要修改的标签,例:1->car,标签数不同删减或增加elif语句即可
- 3、运行xml_change_label.py
- 4、结果展示
运行前:
运行后:
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!!!")
-
代码作用:xml标签格式转换txt标签格式
-
1、修改待修改xml文件夹和目标txt文件夹路径
[外链图片转存失败,源站可能有防盗在这里插入!链机制,建描述]议将图片上https://传(imblog.csnmg.ci/1ngx5f06aa398049420a868e0b560d21fda.png2(https://ig-blog.csdnimg.cn/5f06aa398049420a868e0b5620d21fda.png)]
温馨提示:注意,如果读取当前路径的话,前两个路径要修改成相对路径
- 2、换成待转换xml标签名称所想排顺序的名称序列
- 3、运行xml_txt.py
4、结果展示
运行前:
运行后:
Author: MBJC
Last modification time: 2022/8/2 19:48