前言

您在深度学习领域的探索已经持续了半年时间,最初您选择了YOLOv8模型作为起点。在开始阶段,您亲自采集了数千张图像,并制作了一个数据集,所有的标注都以txt格式保存。随着学习的深入,您萌生了对比YOLOv8与SSD、RCNN等其他模型性能的想法。然而,SSD和RCNN模型需要的是xml格式的标注文件。

面对这一挑战,您意识到重新标注所有图像不仅耗时耗力,而且新的标注很难与原有标注完全一致,这将影响到实验结果的可比性和严谨性。因此,您决定将原有的txt标注文件转换为xml格式,以保持数据的一致性,从而确保实验的准确性和可靠性。

通过这样的转换,您不仅能够充分利用已有的数据集,还能在保持数据一致性的前提下,对不同模型的性能进行公正的比较。这无疑是一个既高效又严谨的解决方案。

Python程序实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
from xml.dom.minidom import Document
import os
import cv2
from tqdm import tqdm


# def makexml(txtPath, xmlPath, picPath): # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径
def makexml(picPath, txtPath, xmlPath, datasetName): # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径
"""此函数用于将yolo格式txt标注文件转换为voc格式xml标注文件
在自己的标注图片文件夹下建三个子文件夹,分别命名为picture、txt、xml
"""
dic = {'0': "Pickable"}
files = os.listdir(txtPath)
for i, name in enumerate(tqdm(files)):
if name == 'classes.txt':
continue
xmlBuilder = Document()
annotation = xmlBuilder.createElement("annotation") # 创建annotation标签
xmlBuilder.appendChild(annotation)
txtFile = open(os.path.join(txtPath, name))
txtList = txtFile.readlines()
img = cv2.imread(os.path.join(picPath, name.replace('txt', 'jpg')))
Pheight, Pwidth, Pdepth = img.shape

folder = xmlBuilder.createElement("folder") # folder标签
foldercontent = xmlBuilder.createTextNode(datasetName)
folder.appendChild(foldercontent)
annotation.appendChild(folder) # folder标签结束

filename = xmlBuilder.createElement("filename") # filename标签
filenamecontent = xmlBuilder.createTextNode(name[0:-4] + ".jpg")
filename.appendChild(filenamecontent)
annotation.appendChild(filename) # filename标签结束

size = xmlBuilder.createElement("size") # size标签
width = xmlBuilder.createElement("width") # size子标签width
widthcontent = xmlBuilder.createTextNode(str(Pwidth))
width.appendChild(widthcontent)
size.appendChild(width) # size子标签width结束

height = xmlBuilder.createElement("height") # size子标签height
heightcontent = xmlBuilder.createTextNode(str(Pheight))
height.appendChild(heightcontent)
size.appendChild(height) # size子标签height结束

depth = xmlBuilder.createElement("depth") # size子标签depth
depthcontent = xmlBuilder.createTextNode(str(Pdepth))
depth.appendChild(depthcontent)
size.appendChild(depth) # size子标签depth结束

annotation.appendChild(size) # size标签结束

for j in txtList:
oneline = j.strip().split(" ")
object = xmlBuilder.createElement("object") # object 标签
picname = xmlBuilder.createElement("name") # name标签
namecontent = xmlBuilder.createTextNode(dic[oneline[0]])
picname.appendChild(namecontent)
object.appendChild(picname) # name标签结束

pose = xmlBuilder.createElement("pose") # pose标签
posecontent = xmlBuilder.createTextNode("Unspecified")
pose.appendChild(posecontent)
object.appendChild(pose) # pose标签结束

truncated = xmlBuilder.createElement("truncated") # truncated标签
truncatedContent = xmlBuilder.createTextNode("0")
truncated.appendChild(truncatedContent)
object.appendChild(truncated) # truncated标签结束

difficult = xmlBuilder.createElement("difficult") # difficult标签
difficultcontent = xmlBuilder.createTextNode("0")
difficult.appendChild(difficultcontent)
object.appendChild(difficult) # difficult标签结束

bndbox = xmlBuilder.createElement("bndbox") # bndbox标签
xmin = xmlBuilder.createElement("xmin") # xmin标签
mathData = int(((float(oneline[1])) * Pwidth + 1) - (float(oneline[3])) * 0.5 * Pwidth)
xminContent = xmlBuilder.createTextNode(str(mathData))
xmin.appendChild(xminContent)
bndbox.appendChild(xmin) # xmin标签结束

ymin = xmlBuilder.createElement("ymin") # ymin标签
mathData = int(((float(oneline[2])) * Pheight + 1) - (float(oneline[4])) * 0.5 * Pheight)
yminContent = xmlBuilder.createTextNode(str(mathData))
ymin.appendChild(yminContent)
bndbox.appendChild(ymin) # ymin标签结束

xmax = xmlBuilder.createElement("xmax") # xmax标签
mathData = int(((float(oneline[1])) * Pwidth + 1) + (float(oneline[3])) * 0.5 * Pwidth)
xmaxContent = xmlBuilder.createTextNode(str(mathData))
xmax.appendChild(xmaxContent)
bndbox.appendChild(xmax) # xmax标签结束

ymax = xmlBuilder.createElement("ymax") # ymax标签
mathData = int(((float(oneline[2])) * Pheight + 1) + (float(oneline[4])) * 0.5 * Pheight)
ymaxContent = xmlBuilder.createTextNode(str(mathData))
ymax.appendChild(ymaxContent)
bndbox.appendChild(ymax) # ymax标签结束

object.appendChild(bndbox) # bndbox标签结束

annotation.appendChild(object) # object标签结束

f = open(os.path.join(xmlPath, name.replace('txt', 'xml')), 'w')
xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')
f.close()

# ann_path = r"G:\CBB-Program\TKK\TKK-SDD\VOCdevkit\VOC2007\111/" # txt文件路径
# img_path = r"G:\CBB-Program\TKK\TKK-SDD\VOCdevkit\VOC2007\JPEGImages/" # 图片路径
# xml_path = r"G:\CBB-Program\TKK\TKK-SDD\VOCdevkit\VOC2007/" # xml保存路径
if __name__ == "__main__":
picPath = r"G:\CBB-Program\TKK-10\TKK-SDD\VOCdevkit\VOC2007\JPEGImages/" # 原图文件夹路径
txtPath = r"G:\CBB-Program\TKK-10\TKK-SDD\VOCdevkit\VOC2007\111/" # 原txt标签文件夹路径
xmlPath = r"G:\CBB-Program\TKK-10\TKK-SDD\VOCdevkit\VOC2007\Annotations/" # 保存xml文件夹路径
datasetName = r'Pickable' # 数据集名称
os.makedirs(xmlPath) if not os.path.exists(xmlPath) else None
makexml(picPath, txtPath, xmlPath, datasetName)

需要修改内容

本程序仅仅适用一个标签的数据集,如果有多个标签,可以按照这个程序自行修改

  • 修改第10行,需要替换“标签名称”为自己的数据集标签
1
dic = {'0': "标签名称"}
  • 修改第108行,需要替换”原图文件夹路径”为自己的原图文件夹路径
1
picPath = r"原图文件夹路径"         # 原图文件夹路径
  • 修改第109行,需要替换”原txt标签文件夹路径”为自己的原txt标签文件夹路径
1
txtPath = r"原txt标签文件夹路径"    # 原txt标签文件夹路径
  • 修改第110行,需要替换”保存xml文件夹路径”为自己的保存xml文件夹路径
1
xmlPath = r"保存xml文件夹路径"    # 保存xml文件夹路径
  • 修改第111行,需要替换’数据集名称’为自己的数据集名称
1
datasetName = r'数据集名称'      # 数据集名称