coco與voc相互轉化

把LabelImg標注的YOLO格式標簽轉化為VOC格式標簽 和 把VOC格式標簽轉化為YOLO格式標簽

點亮~黑夜 2020-07-07 11:08:24 ?3537 ?已收藏 90
分類專欄: 19—目標檢測 文章標簽: voc yolo
版權
把LabelImg標注的YOLO格式標簽轉化為VOC格式標簽 和 把VOC格式標簽轉化為YOLO格式標簽

文章目錄:
1 用LabelImgvoc和yolo標注標簽格式說明
1.1 LabelImg標注的VOC數據格式
1.2 LabelImg標注的YOLO數據格式
2 voc轉換為yolo格式計算
3 yolo轉換為voc格式計算
4 yolo格式標簽轉化為voc格式標簽代碼
5 VOC格式標簽轉化為YOLO格式標簽代碼
1 用LabelImgvoc和yolo標注標簽格式說明
關于LabelImg工具的使用,參考

1.1 LabelImg標注的VOC數據格式
VOC數據格式,會直接把每張圖片標注的標簽信息保存到一個xml文件中

例如:我們上面標注的JPEGImage/000001.jpg圖片,標注的標簽信息會保存到Annotation/000001.xml文件中,000001.xml中的信息如下:

<annotation>
?? ?<folder>JPEGImage</folder>
?? ?<filename>000000.jpg</filename>
?? ?<path>D:\ZF\2_ZF_data\3_stamp_data\標注公章數據\JPEGImage\000000.jpg</path>
?? ?<source>
?? ??? ?<database>Unknown</database>
?? ?</source>
?? ?<size>
?? ??? ?<width>500</width>
?? ??? ?<height>402</height>
?? ??? ?<depth>3</depth>
?? ?</size>
?? ?<segmented>0</segmented>
?? ?<object>
?? ??? ?<name>circle_red</name>
?? ??? ?<pose>Unspecified</pose>
?? ??? ?<truncated>0</truncated>
?? ??? ?<difficult>0</difficult>
?? ??? ?<bndbox>
?? ??? ??? ?<xmin>168</xmin>
?? ??? ??? ?<ymin>2</ymin>
?? ??? ??? ?<xmax>355</xmax>
?? ??? ??? ?<ymax>186</ymax>
?? ??? ?</bndbox>
?? ?</object>
?? ?<object>
?? ??? ?<name>circle_red</name>
?? ??? ?<pose>Unspecified</pose>
?? ??? ?<truncated>0</truncated>
?? ??? ?<difficult>0</difficult>
?? ??? ?<bndbox>
?? ??? ??? ?<xmin>2</xmin>
?? ??? ??? ?<ymin>154</ymin>
?? ??? ??? ?<xmax>208</xmax>
?? ??? ??? ?<ymax>367</ymax>
?? ??? ?</bndbox>
?? ?</object>
?? ?<object>
?? ??? ?<name>circle_red</name>
?? ??? ?<pose>Unspecified</pose>
?? ??? ?<truncated>0</truncated>
?? ??? ?<difficult>0</difficult>
?? ??? ?<bndbox>
?? ??? ??? ?<xmin>305</xmin>
?? ??? ??? ?<ymin>174</ymin>
?? ??? ??? ?<xmax>493</xmax>
?? ??? ??? ?<ymax>364</ymax>
?? ??? ?</bndbox>
?? ?</object>
</annotation>

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
xml中的關鍵信息說明:

圖片的名字
每個目標的標定框坐標:即左上角的坐標和右下角的坐標
xmin
ymin
xmax
ymax
1.2 LabelImg標注的YOLO數據格式
YOLO數據格式,會直接把每張圖片標注的標簽信息保存到一個txt文件中

例如:我們上面標注的JPEGImage/000001.jpg圖片,標注的標簽信息會保存到Annotation/000001.txt文件中(同時會生成一個classes.txt文件,也保存到Annotation/classes.txt),000001.txt中的信息如下:

0 0.521000 0.235075 0.362000 0.450249
0 0.213000 0.645522 0.418000 0.519900
0 0.794000 0.665423 0.376000 0.470149
1
2
3
txt中信息說明:

每一行代表標注的一個目標
第一個數代表標注目標的標簽,第一目標circle_red,對應數字就是0
后面的四個數代表標注框的中心坐標和標注框的相對寬和高(進行了歸一化,如何歸一化可以參考我的這篇博客中的介紹)
五個數據從左到右以此為:c l a s s _ i n d e x , x _ c e n t e r , y _ c e n t e r , w , h class\_index, x\_center, y\_center, w, hclass_index,x_center,y_center,w,h。(后面的四個數據都是歸一化的)
同時會生成一個Annotation/classes.txt實際類別文件classes.txt,里面的內容如下:

circle_red
circle_gray
rectangle_red
rectangle_gray
fingeprint_red
fingeprint_gray
other
1
2
3
4
5
6
7
2 voc轉換為yolo格式計算
標注好的VOC格式的標簽xml文件,存儲的主要信息為:

圖片的名字
圖片的高height、寬width、通道depth
標定框的坐標位置:xmin、ymin、xmax、ymax
例如下圖代表的是一樣圖片:

紅框代表的是原圖大小:height=8,width=8
藍框代表的是標注物體的框:左上角坐標為 (xmin, ymin)=(2,2),右下角的坐標為 (xmax, ymax)=(6,6)

而voc_label.py目的就是把標注為VOC格式數據轉化為標注為yolo格式數據:
VOC格式標簽:圖片的實際寬和高,標注框的左上角和右下角坐標
YOLO格式標簽:標注框的中心坐標(歸一化的),標注框的寬和高(歸一化的)
VOC格式標簽轉換為YOLO格式標簽計算公式:

框中心的實際坐標(x, y):(一般可能還會在后面減去1)
x _ c e n t e r = x m a x + x m i n 2 = 6 + 2 2 = 4 x\_center=\frac{xmax+xmin}{2}=\frac{6+2}{2}=4
x_center=?
2
xmax+xmin
??? ?
?=?
2
6+2
??? ?
?=4

y _ c e n t e r = y m a x + y m i n 2 = 6 + 2 2 = 4 y\_center=\frac{ymax+ymin}{2}=\frac{6+2}{2}=4
y_center=?
2
ymax+ymin
??? ?
?=?
2
6+2
??? ?
?=4

框歸一化后的中心坐標(x, y):
x = x _ c e n t e r w i d t h = 4 8 = 0.5 x=\frac{x\_center}{width}=\frac{4}{8}=0.5
x=?
width
x_center
??? ?
?=?
8
4
??? ?
?=0.5

y = y _ c e n t e r h e i g h t = 4 8 = 0.5 y=\frac{y\_center}{height}=\frac{4}{8}=0.5
y=?
height
y_center
??? ?
?=?
8
4
??? ?
?=0.5

框的高和框(歸一化的):
w = x m a x ? x m i n w i d t h = 6 ? 2 8 = 0.5 w=\frac{xmax-xmin}{width}=\frac{6-2}{8}=0.5
w=?
width
xmax?xmin
??? ?
?=?
8
6?2
??? ?
?=0.5

h = y m a x ? y m i n h e i g h t = 6 ? 2 8 = 0.5 h=\frac{ymax-ymin}{height}=\frac{6-2}{8}=0.5
h=?
height
ymax?ymin
??? ?
?=?
8
6?2
??? ?
?=0.5

3 yolo轉換為voc格式計算
voc中保存的坐標信息為:xmin, ymin, xmax, ymax,所以只要根據上面的公式,推導出這四個值即可,推導如下:

推導:xmin, xmax
{ x m a x + x m i n = 2 x _ c e n t e r x m a x ? x m i n = w ? w i d t h
{xmax+xmin=2x_centerxmax?xmin=w?width
{xmax+xmin=2x_centerxmax?xmin=w?width
{?
xmax+xmin=2x_center
xmax?xmin=w?width
??? ?
?

{ 2 x m a x = 2 x _ c e n t e r + w ? w i d t h = > x m a x = x _ c e n t e r + 1 2 ? w ? w i d t h 2 x m i n = 2 x _ c e n t e r ? w ? w i d t h = > x m i n = x _ c e n t e r ? 1 2 ? w ? w i d t h
{2xmax=2x_center+w?width=>xmax=x_center+12?w?width2xmin=2x_center?w?width=>xmin=x_center?12?w?width
{2xmax=2x_center+w?width=>xmax=x_center+12?w?width2xmin=2x_center?w?width=>xmin=x_center?12?w?width
{?
2xmax=2x_center+w?width=>xmax=x_center+?
2
1
??? ?
??w?width
2xmin=2x_center?w?width=>xmin=x_center??
2
1
??? ?
??w?width
??? ?
?

推導:ymin, ymax
{ y m a x + y m i n = 2 y _ c e n t e r y m a x ? y m i n = y ? h e i g h t
{ymax+ymin=2y_centerymax?ymin=y?height
{ymax+ymin=2y_centerymax?ymin=y?height
{?
ymax+ymin=2y_center
ymax?ymin=y?height
??? ?
?

{ 2 y m a x = 2 y _ c e n t e r + h ? h e i g h t = > y m a x = y _ c e n t e r + 1 2 ? h ? h e i g h t 2 y m i n = 2 y _ c e n t e r ? h ? h e i g h t = > y m i n = y _ c e n t e r ? 1 2 ? h ? h e i g h t
{2ymax=2y_center+h?height=>ymax=y_center+12?h?height2ymin=2y_center?h?height=>ymin=y_center?12?h?height
{2ymax=2y_center+h?height=>ymax=y_center+12?h?height2ymin=2y_center?h?height=>ymin=y_center?12?h?height
{?
2ymax=2y_center+h?height=>ymax=y_center+?
2
1
??? ?
??h?height
2ymin=2y_center?h?height=>ymin=y_center??
2
1
??? ?
??h?height
??? ?
?

4 yolo格式標簽轉化為voc格式標簽代碼
代碼是把txt標簽轉化為voc標簽
代碼支持一個標簽文件中有多個目標
__Author__ = "Shliang"
__Email__ = "shliang0603@gmail.com"

import os
import xml.etree.ElementTree as ET
from xml.dom.minidom import Document
import cv2


'''
import xml
xml.dom.minidom.Document().writexml()
def writexml(self,
? ? ? ? ? ? ?writer: Any,
? ? ? ? ? ? ?indent: str = "",
? ? ? ? ? ? ?addindent: str = "",
? ? ? ? ? ? ?newl: str = "",
? ? ? ? ? ? ?encoding: Any = None) -> None
'''

class YOLO2VOCConvert:
? ? def __init__(self, txts_path, xmls_path, imgs_path):
? ? ? ? self.txts_path = txts_path ? # 標注的yolo格式標簽文件路徑
? ? ? ? self.xmls_path = xmls_path ? # 轉化為voc格式標簽之后保存路徑
? ? ? ? self.imgs_path = imgs_path ? # 讀取讀片的路徑個圖片名字,存儲到xml標簽文件中
? ? ? ? self.classes = ["shirt", "non_shirt", "western_style_clothes", "coat", "down_filled_coat",
? ? ? ? ? ? ? ? ? ? ? ? "cotton", "sweater", "silk_scarf", "tie", "bow_tie"]

? ? # 從所有的txt文件中提取出所有的類別, yolo格式的標簽格式類別為數字 0,1,...
? ? # writer為True時,把提取的類別保存到'./Annotations/classes.txt'文件中
? ? def search_all_classes(self, writer=False):
? ? ? ? # 讀取每一個txt標簽文件,取出每個目標的標注信息
? ? ? ? all_names = set()
? ? ? ? txts = os.listdir(self.txts_path)
? ? ? ? # 使用列表生成式過濾出只有后綴名為txt的標簽文件
? ? ? ? txts = [txt for txt in txts if txt.split('.')[-1] == 'txt']
? ? ? ? print(len(txts), txts)
? ? ? ? # 11 ['0002030.txt', '0002031.txt', ... '0002039.txt', '0002040.txt']
? ? ? ? for txt in txts:
? ? ? ? ? ? txt_file = os.path.join(self.txts_path, txt)
? ? ? ? ? ? with open(txt_file, 'r') as f:
? ? ? ? ? ? ? ? objects = f.readlines()
? ? ? ? ? ? ? ? for object in objects:
? ? ? ? ? ? ? ? ? ? object = object.strip().split(' ')
? ? ? ? ? ? ? ? ? ? print(object) ?# ['2', '0.506667', '0.553333', '0.490667', '0.658667']
? ? ? ? ? ? ? ? ? ? all_names.add(int(object[0]))
? ? ? ? ? ? # print(objects) ?# ['2 0.506667 0.553333 0.490667 0.658667\n', '0 0.496000 0.285333 0.133333 0.096000\n', '8 0.501333 0.412000 0.074667 0.237333\n']

? ? ? ? print("所有的類別標簽:", all_names, "共標注數據集:%d張" % len(txts))

? ? ? ? # 把從xmls標簽文件中提取的類別寫入到'./Annotations/classes.txt'文件中
? ? ? ? # if writer:
? ? ? ? # ? ? with open('./Annotations/classes.txt', 'w') as f:
? ? ? ? # ? ? ? ? for label in all_names:
? ? ? ? # ? ? ? ? ? ? f.write(label + '\n')

? ? ? ? return list(all_names)

? ? def yolo2voc(self):
? ? ? ? # 創建一個保存xml標簽文件的文件夾
? ? ? ? if not os.path.exists(self.xmls_path):
? ? ? ? ? ? os.mkdir(self.xmls_path)

? ? ? ? # # 讀取每張圖片,獲取圖片的尺寸信息(shape)
? ? ? ? # imgs = os.listdir(self.imgs_path)
? ? ? ? # for img_name in imgs:
? ? ? ? # ? ? img = cv2.imread(os.path.join(self.imgs_path, img_name))
? ? ? ? # ? ? height, width, depth = img.shape
? ? ? ? # ? ? # print(height, width, depth) ? # h 就是多少行(對應圖片的高度), w就是多少列(對應圖片的寬度)
? ? ? ? #
? ? ? ? # # 讀取每一個txt標簽文件,取出每個目標的標注信息
? ? ? ? # all_names = set()
? ? ? ? # txts = os.listdir(self.txts_path)
? ? ? ? # # 使用列表生成式過濾出只有后綴名為txt的標簽文件
? ? ? ? # txts = [txt for txt in txts if txt.split('.')[-1] == 'txt']
? ? ? ? # print(len(txts), txts)
? ? ? ? # # 11 ['0002030.txt', '0002031.txt', ... '0002039.txt', '0002040.txt']
? ? ? ? # for txt_name in txts:
? ? ? ? # ? ? txt_file = os.path.join(self.txts_path, txt_name)
? ? ? ? # ? ? with open(txt_file, 'r') as f:
? ? ? ? # ? ? ? ? objects = f.readlines()
? ? ? ? # ? ? ? ? for object in objects:
? ? ? ? # ? ? ? ? ? ? object = object.strip().split(' ')
? ? ? ? # ? ? ? ? ? ? print(object) ?# ['2', '0.506667', '0.553333', '0.490667', '0.658667']

? ? ? ? # 把上面的兩個循環改寫成為一個循環:
? ? ? ? imgs = os.listdir(self.imgs_path)
? ? ? ? txts = os.listdir(self.txts_path)
? ? ? ? txts = [txt for txt in txts if not txt.split('.')[0] == "classes"] ?# 過濾掉classes.txt文件
? ? ? ? print(txts)
? ? ? ? # 注意,這里保持圖片的數量和標簽txt文件數量相等,且要保證名字是一一對應的 ? (后面改進,通過判斷txt文件名是否在imgs中即可)
? ? ? ? if len(imgs) == len(txts): ? # 注意:./Annotation_txt 不要把classes.txt文件放進去
? ? ? ? ? ? map_imgs_txts = [(img, txt) for img, txt in zip(imgs, txts)]
? ? ? ? ? ? txts = [txt for txt in txts if txt.split('.')[-1] == 'txt']
? ? ? ? ? ? print(len(txts), txts)
? ? ? ? ? ? for img_name, txt_name in map_imgs_txts:
? ? ? ? ? ? ? ? # 讀取圖片的尺度信息
? ? ? ? ? ? ? ? print("讀取圖片:", img_name)
? ? ? ? ? ? ? ? img = cv2.imread(os.path.join(self.imgs_path, img_name))
? ? ? ? ? ? ? ? height_img, width_img, depth_img = img.shape
? ? ? ? ? ? ? ? print(height_img, width_img, depth_img) ? # h 就是多少行(對應圖片的高度), w就是多少列(對應圖片的寬度)

? ? ? ? ? ? ? ? # 獲取標注文件txt中的標注信息
? ? ? ? ? ? ? ? all_objects = []
? ? ? ? ? ? ? ? txt_file = os.path.join(self.txts_path, txt_name)
? ? ? ? ? ? ? ? with open(txt_file, 'r') as f:
? ? ? ? ? ? ? ? ? ? objects = f.readlines()
? ? ? ? ? ? ? ? ? ? for object in objects:
? ? ? ? ? ? ? ? ? ? ? ? object = object.strip().split(' ')
? ? ? ? ? ? ? ? ? ? ? ? all_objects.append(object)
? ? ? ? ? ? ? ? ? ? ? ? print(object) ?# ['2', '0.506667', '0.553333', '0.490667', '0.658667']

? ? ? ? ? ? ? ? # 創建xml標簽文件中的標簽
? ? ? ? ? ? ? ? xmlBuilder = Document()
? ? ? ? ? ? ? ? # 創建annotation標簽,也是根標簽
? ? ? ? ? ? ? ? annotation = xmlBuilder.createElement("annotation")

? ? ? ? ? ? ? ? # 給標簽annotation添加一個子標簽
? ? ? ? ? ? ? ? xmlBuilder.appendChild(annotation)

? ? ? ? ? ? ? ? # 創建子標簽folder
? ? ? ? ? ? ? ? folder = xmlBuilder.createElement("folder")
? ? ? ? ? ? ? ? # 給子標簽folder中存入內容,folder標簽中的內容是存放圖片的文件夾,例如:JPEGImages
? ? ? ? ? ? ? ? folderContent = xmlBuilder.createTextNode(self.imgs_path.split('/')[-1]) ?# 標簽內存
? ? ? ? ? ? ? ? folder.appendChild(folderContent) ?# 把內容存入標簽
? ? ? ? ? ? ? ? annotation.appendChild(folder) ? # 把存好內容的folder標簽放到 annotation根標簽下

? ? ? ? ? ? ? ? # 創建子標簽filename
? ? ? ? ? ? ? ? filename = xmlBuilder.createElement("filename")
? ? ? ? ? ? ? ? # 給子標簽filename中存入內容,filename標簽中的內容是圖片的名字,例如:000250.jpg
? ? ? ? ? ? ? ? filenameContent = xmlBuilder.createTextNode(txt_name.split('.')[0] + '.jpg') ?# 標簽內容
? ? ? ? ? ? ? ? filename.appendChild(filenameContent)
? ? ? ? ? ? ? ? annotation.appendChild(filename)

? ? ? ? ? ? ? ? # 把圖片的shape存入xml標簽中
? ? ? ? ? ? ? ? size = xmlBuilder.createElement("size")
? ? ? ? ? ? ? ? # 給size標簽創建子標簽width
? ? ? ? ? ? ? ? width = xmlBuilder.createElement("width") ?# size子標簽width
? ? ? ? ? ? ? ? widthContent = xmlBuilder.createTextNode(str(width_img))
? ? ? ? ? ? ? ? width.appendChild(widthContent)
? ? ? ? ? ? ? ? size.appendChild(width) ? # 把width添加為size的子標簽
? ? ? ? ? ? ? ? # 給size標簽創建子標簽height
? ? ? ? ? ? ? ? height = xmlBuilder.createElement("height") ?# size子標簽height
? ? ? ? ? ? ? ? heightContent = xmlBuilder.createTextNode(str(height_img)) ?# xml標簽中存入的內容都是字符串
? ? ? ? ? ? ? ? height.appendChild(heightContent)
? ? ? ? ? ? ? ? size.appendChild(height) ?# 把width添加為size的子標簽
? ? ? ? ? ? ? ? # 給size標簽創建子標簽depth
? ? ? ? ? ? ? ? depth = xmlBuilder.createElement("depth") ?# size子標簽width
? ? ? ? ? ? ? ? depthContent = xmlBuilder.createTextNode(str(depth_img))
? ? ? ? ? ? ? ? depth.appendChild(depthContent)
? ? ? ? ? ? ? ? size.appendChild(depth) ?# 把width添加為size的子標簽
? ? ? ? ? ? ? ? annotation.appendChild(size) ? # 把size添加為annotation的子標簽

? ? ? ? ? ? ? ? # 每一個object中存儲的都是['2', '0.506667', '0.553333', '0.490667', '0.658667']一個標注目標
? ? ? ? ? ? ? ? for object_info in all_objects:
? ? ? ? ? ? ? ? ? ? # 開始創建標注目標的label信息的標簽
? ? ? ? ? ? ? ? ? ? object = xmlBuilder.createElement("object") ?# 創建object標簽
? ? ? ? ? ? ? ? ? ? # 創建label類別標簽
? ? ? ? ? ? ? ? ? ? # 創建name標簽
? ? ? ? ? ? ? ? ? ? imgName = xmlBuilder.createElement("name") ?# 創建name標簽
? ? ? ? ? ? ? ? ? ? imgNameContent = xmlBuilder.createTextNode(self.classes[int(object_info[0])])
? ? ? ? ? ? ? ? ? ? imgName.appendChild(imgNameContent)
? ? ? ? ? ? ? ? ? ? object.appendChild(imgName) ?# 把name添加為object的子標簽

? ? ? ? ? ? ? ? ? ? # 創建pose標簽
? ? ? ? ? ? ? ? ? ? pose = xmlBuilder.createElement("pose")
? ? ? ? ? ? ? ? ? ? poseContent = xmlBuilder.createTextNode("Unspecified")
? ? ? ? ? ? ? ? ? ? pose.appendChild(poseContent)
? ? ? ? ? ? ? ? ? ? object.appendChild(pose) ?# 把pose添加為object的標簽

? ? ? ? ? ? ? ? ? ? # 創建truncated標簽
? ? ? ? ? ? ? ? ? ? truncated = xmlBuilder.createElement("truncated")
? ? ? ? ? ? ? ? ? ? truncatedContent = xmlBuilder.createTextNode("0")
? ? ? ? ? ? ? ? ? ? truncated.appendChild(truncatedContent)
? ? ? ? ? ? ? ? ? ? object.appendChild(truncated)

? ? ? ? ? ? ? ? ? ? # 創建difficult標簽
? ? ? ? ? ? ? ? ? ? difficult = xmlBuilder.createElement("difficult")
? ? ? ? ? ? ? ? ? ? difficultContent = xmlBuilder.createTextNode("0")
? ? ? ? ? ? ? ? ? ? difficult.appendChild(difficultContent)
? ? ? ? ? ? ? ? ? ? object.appendChild(difficult)

? ? ? ? ? ? ? ? ? ? # 先轉換一下坐標
? ? ? ? ? ? ? ? ? ? # (objx_center, objy_center, obj_width, obj_height)->(xmin,ymin, xmax,ymax)
? ? ? ? ? ? ? ? ? ? x_center = float(object_info[1])*width_img + 1
? ? ? ? ? ? ? ? ? ? y_center = float(object_info[2])*height_img + 1
? ? ? ? ? ? ? ? ? ? xminVal = int(x_center - 0.5*float(object_info[3])*width_img) ? # object_info列表中的元素都是字符串類型
? ? ? ? ? ? ? ? ? ? yminVal = int(y_center - 0.5*float(object_info[4])*height_img)
? ? ? ? ? ? ? ? ? ? xmaxVal = int(x_center + 0.5*float(object_info[3])*width_img)
? ? ? ? ? ? ? ? ? ? ymaxVal = int(y_center + 0.5*float(object_info[4])*height_img)

? ? ? ? ? ? ? ? ? ? # 創建bndbox標簽(三級標簽)
? ? ? ? ? ? ? ? ? ? bndbox = xmlBuilder.createElement("bndbox")
? ? ? ? ? ? ? ? ? ? # 在bndbox標簽下再創建四個子標簽(xmin,ymin, xmax,ymax) 即標注物體的坐標和寬高信息
? ? ? ? ? ? ? ? ? ? # 在voc格式中,標注信息:左上角坐標(xmin, ymin) (xmax, ymax)右下角坐標
? ? ? ? ? ? ? ? ? ? # 1、創建xmin標簽
? ? ? ? ? ? ? ? ? ? xmin = xmlBuilder.createElement("xmin") ?# 創建xmin標簽(四級標簽)
? ? ? ? ? ? ? ? ? ? xminContent = xmlBuilder.createTextNode(str(xminVal))
? ? ? ? ? ? ? ? ? ? xmin.appendChild(xminContent)
? ? ? ? ? ? ? ? ? ? bndbox.appendChild(xmin)
? ? ? ? ? ? ? ? ? ? # 2、創建ymin標簽
? ? ? ? ? ? ? ? ? ? ymin = xmlBuilder.createElement("ymin") ?# 創建ymin標簽(四級標簽)
? ? ? ? ? ? ? ? ? ? yminContent = xmlBuilder.createTextNode(str(yminVal))
? ? ? ? ? ? ? ? ? ? ymin.appendChild(yminContent)
? ? ? ? ? ? ? ? ? ? bndbox.appendChild(ymin)
? ? ? ? ? ? ? ? ? ? # 3、創建xmax標簽
? ? ? ? ? ? ? ? ? ? xmax = xmlBuilder.createElement("xmax") ?# 創建xmax標簽(四級標簽)
? ? ? ? ? ? ? ? ? ? xmaxContent = xmlBuilder.createTextNode(str(xmaxVal))
? ? ? ? ? ? ? ? ? ? xmax.appendChild(xmaxContent)
? ? ? ? ? ? ? ? ? ? bndbox.appendChild(xmax)
? ? ? ? ? ? ? ? ? ? # 4、創建ymax標簽
? ? ? ? ? ? ? ? ? ? ymax = xmlBuilder.createElement("ymax") ?# 創建ymax標簽(四級標簽)
? ? ? ? ? ? ? ? ? ? ymaxContent = xmlBuilder.createTextNode(str(ymaxVal))
? ? ? ? ? ? ? ? ? ? ymax.appendChild(ymaxContent)
? ? ? ? ? ? ? ? ? ? bndbox.appendChild(ymax)

? ? ? ? ? ? ? ? ? ? object.appendChild(bndbox)
? ? ? ? ? ? ? ? ? ? annotation.appendChild(object) ?# 把object添加為annotation的子標簽
? ? ? ? ? ? ? ? f = open(os.path.join(self.xmls_path, txt_name.split('.')[0]+'.xml'), 'w')
? ? ? ? ? ? ? ? xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')
? ? ? ? ? ? ? ? f.close()


if __name__ == '__main__':
? ? txts_path1 = './Annotations_txt'
? ? xmls_path1 = './Annotations_xml'
? ? imgs_path1 = './JPEGImages'

? ? yolo2voc_obj1 = YOLO2VOCConvert(txts_path1, xmls_path1, imgs_path1)
? ? labels = yolo2voc.search_all_classes()
? ? print('labels: ', labels)
? ? yolo2voc_obj1.yolo2voc()
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
5 VOC格式標簽轉化為YOLO格式標簽代碼
代碼參考

Github yolov3:https://github.com/AlexeyAB/darknet/blob/master/scripts/voc_label.py
YOLO官網:https://pjreddie.com/media/files/voc_label.py
把標注的VOC格式的.xml標簽文件,轉化為YOLO格式的txt標簽文件

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join

# classes = ['hard_hat', 'other', 'regular', 'long_hair', 'braid', 'bald', 'beard']

def convert(size, box):
? ? # size=(width, height) ?b=(xmin, xmax, ymin, ymax)
? ? # x_center = (xmax+xmin)/2 ? ? ? ?y_center = (ymax+ymin)/2
? ? # x = x_center / width ? ? ? ? ? ?y = y_center / height
? ? # w = (xmax-xmin) / width ? ? ? ? h = (ymax-ymin) / height
? ??
? ? x_center = (box[0]+box[1])/2.0
? ? y_center = (box[2]+box[3])/2.0
? ? x = x_center / size[0]
? ? y = y_center / size[1]

? ? w = (box[1] - box[0]) / size[0]
? ? h = (box[3] - box[2]) / size[1]
? ??
? ? # print(x, y, w, h)
? ? return (x,y,w,h)


def convert_annotation(xml_files_path, save_txt_files_path, classes): ?
? ? xml_files = os.listdir(xml_files_path)
? ? print(xml_files)
? ? for xml_name in xml_files:
? ? ? ? print(xml_name)
? ? ? ? xml_file = os.path.join(xml_files_path, xml_name)
? ? ? ? out_txt_path = os.path.join(save_txt_files_path, xml_name.split('.')[0] + '.txt')
? ? ? ? out_txt_f = open(out_txt_path, 'w')
? ? ? ? tree=ET.parse(xml_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))
? ? ? ? ? ? # b=(xmin, xmax, ymin, ymax)
? ? ? ? ? ? print(w, h, b)
? ? ? ? ? ? bb = convert((w,h), b)
? ? ? ? ? ? out_txt_f.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')


if __name__ == "__main__":
? ? # 測試程序
? ? # classes = ['hard_hat', 'other', 'regular', 'long_hair', 'braid', 'bald', 'beard']
? ? # xml_files = r'D:\ZF\1_ZF_proj\3_腳本程序\2_voc格式轉yolo格式\voc_labels'
? ? # save_txt_files = r'D:\ZF\1_ZF_proj\3_腳本程序\2_voc格式轉yolo格式\yolo_labels'
? ? # convert_annotation(xml_files, save_txt_files, classes)

? ? #====================================================================================================
? ? # 把帽子頭發胡子的voc的xml標簽文件轉化為yolo的txt標簽文件
? ? # 1、帽子頭發胡子的類別
? ? classes1 = ['hard_hat', 'other', 'regular', 'long_hair', 'braid', 'bald', 'beard']
? ? # 2、voc格式的xml標簽文件路徑
? ? xml_files1 = r'D:\ZF\2_ZF_data\19_Yolov5_dataset\VOCdevkit_hat_hair_beard_補過標簽_合并類別\VOC2007\Annotations_合并類別之后的標簽'
? ? # 3、轉化為yolo格式的txt標簽文件存儲路徑
? ? save_txt_files1 = r'D:\ZF\2_ZF_data\19_Yolov5_dataset\VOCdevkit_hat_hair_beard_yolo\labels'

? ? convert_annotation(xml_files1, save_txt_files1, classes1)
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

? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ? ⊕ ?
————————————————
版權聲明:本文為CSDN博主「點亮~黑夜」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_41010198/article/details/107175968

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/251943.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251943.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251943.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

angular中封裝fancyBox(圖片預覽)

首先在官網下載最新版的fancyBox(一定要去最新網站&#xff0c;以前依賴的jquery版本偏低)&#xff0c;附上鏈接&#xff1a;http://fancyapps.com/fancybox/3/ 然后在項目中引用jquery&#xff0c;然后在引用jquery.fancybox.min.css和jquery.fancybox.min.js。 如果需要動畫和…

十二省聯考題解 - JLOI2019 題解

十二省聯考題解 - JLOI2019 題解 兩個T3的難度較大 平均代碼量遠大于去年省選 套路題考查居多 A 難度等級 1 $n^2$暴力可以拿到$60$分的優秀成績 然后可以想到把區間異或轉化為前綴兩點異或 可以想到使用二分答案的方法可持久化Trie解決&#xff0c;但是時間復雜度為$n\log^2 (…

前端vue的get和post請求

vue的get和post需要兩個文件vue.js和vue-resource.js 以下是實現的代碼&#xff0c;可以參考一下&#xff0c;需要注意的接口的請求需要考慮跨域的問題&#xff0c;其次就是訪問頁面需要在tomcat下訪問&#xff0c;否則也會報跨域的問題 <!DOCTYPE html> <html lang&q…

[Vijos 1143]三取方格數

Description 設有N*N的方格圖&#xff0c;我們將其中的某些方格填入正整數&#xff0c; 而其他的方格中放入0。 某人從圖得左上角出發&#xff0c;可以向下走&#xff0c;也可以向右走&#xff0c;直到到達右下角。 在走過的路上&#xff0c;他取走了方格中的數。&#xff08;取…

線掃相機相關規格說明

工業線陣相機與面陣相機特點分析 點滴成海~ 2018-06-29 13:50:38 12184 收藏 29 分類專欄&#xff1a; intership 文章標簽&#xff1a; 視覺元件分析 版權 最近在公司實習&#xff0c;實習中的項目是使用的是微視的一款線陣相機&#xff08;Microview MVC1024DLM-GE35&…

postgresql 不同數據庫不同模式下的數據遷移

編寫不容易,轉載請注明出處謝謝, 數據遷移 因為之前爬蟲的時候&#xff0c;一部分數據并沒有上傳到服務器&#xff0c;在本地。本來用的就是postgresql&#xff0c;也沒用多久&#xff0c;數據遷移的時候&#xff0c;也遇到了很多問題&#xff0c;第一次使pg_dump xx > file…

Oracle中主鍵自增長

最近在學習Oracle和MySql&#xff0c;MySql有自動配置主鍵自增長auto_increment&#xff0c;這樣在輸入數據的時候可以不考慮主鍵的添加&#xff0c;方便對數據庫的操作。 在Oracle中設置自增長首先用到sequence序列&#xff1b; 以創建學生表為例&#xff1a; create table St…

3.單例模式

public class Singleton {//定義私有的靜態變量 private static Singleton singleton;//私有化構造函數private Singleton(){}//獲取實例public static Singleton getInstance(){//同步前判斷避免同步的性能損耗if(nullsingleton){//預防多線程問題synchronized(Singleton.clas…

docker與mmdetection

這里不再介紹 mmdetection 的安裝和配置&#xff0c;使用 mmdetection 較簡單的方法是使用已安裝 mmdetection 的 docker 容器。這樣直接省去了安裝 mmdetection 的過程&#xff0c;讓重心放在模型訓練上&#xff01; 如果你對 docker 和 mmdetection 還不是很熟悉&#xff0c…

互聯網平臺掘金三四五線城市,你需要知道的9.9個真相

互聯網上半場結束&#xff0c;一二線城市流量紅利消失&#xff0c;許多互聯網平臺、投資機構一度經歷至黑之夜。融資失敗、公司倒閉、大裁員迭出。對比鮮明的是&#xff0c;深耕三四五線城市的互聯網平臺正在迅猛崛起。春節期間&#xff0c;小部分敏銳的業者注意到互聯網產品在…

平滑重啟更新(GR機制)

平滑重啟更新&#xff08;GR機制&#xff09; 什么是平滑啟動機制 是一種在協議重啟時保證轉發業務不中斷的機制。什么時候用到平滑重啟 平滑重啟一般應用于業務更新或者版本發布過程中&#xff0c;能夠避免因為代碼發布重啟服務導致的暫時性服務不可用的影響。ngnix 平滑重啟和…

正斜杠( / )和反斜杠( \ )的區別

反斜杠“\”是電腦出現了之后為了表示程序設計里的特殊含義才發明的專用標點。所以除了程序設計領域外&#xff0c;任何地方都不應該使用反斜杠。 如何區分正反斜杠 英語&#xff1a;"/" 英文是forward slash, “\" 是backward slash形象些比喻的話&#xff0c;…

MMDetectionV2 + Colab

MMDetectionV2 Colab 超詳細教程及踩坑實錄 文章目錄 前言一、環境配置二、準備自己的數據集 Aug.14更新三&#xff1a;修改config文件 3.1 文件結構3.2 &#xff08;本地&#xff09;修改config文件 3.2.1 &#xff08;本地&#xff09;構造自己模型的權重文件3.2.2 &#x…

剛剛,OpenStack 第 19 個版本來了,附28項特性詳細解讀!

剛剛&#xff0c;OpenStack 第 19 個版本來了&#xff0c;附28項特性詳細解讀&#xff01; OpenStack Stein版本引入了新的多云編排功能&#xff0c;以及幫助實現邊緣計算用例的增強功能。 OpenStack由一系列相互關聯的項目組成&#xff0c;這些項目可以以不同的組合方式組合在…

SQL作業:綜合練習(二)的返評

一&#xff1a;作業題目&#xff1a;綜合練習&#xff08;二&#xff09; 二&#xff1a;題目要求&#xff1a; 1、創建數據庫CPXS&#xff0c;保存于E盤根目錄下以自己學號姓第一個字母&#xff08;阿拉伯數字大寫字母&#xff09;方式創建的文件夾中&#xff0c;初始大小5MB&…

caffe cifar10試跑問題總結

caffe cifar10試跑問題總結 [daniel] 寫了一個腳本可以直接用來添加環境變量&#xff1a;/Users/songdanzju/daniel_script/export_for_ananconda.sh#! /bin/bash export PATH~/ananconda/bin:$PATH export DYLD_FALLBACK_LIBRARY_PATH~/anaconda:~/anaconda/lib:/usr/local/l…

paddlepaddle-VisualDL2.0對項目進行可視化調參

如果需要更好的閱讀體驗&#xff0c;可以在ai studio上fork該項目&#xff1a;使用VisualDL2.0對項目進行可視化調參 調參是深度學習必須要做的事情。數據和模型處理好后&#xff0c;需要進行模型訓練&#xff0c;這個時候就需要進行調參了。一種好的參數配置&#xff0c;可以…

第一、二次實訓作業

1.編寫程序&#xff1a; 聲明一個整型變量a&#xff0c;并賦初值5&#xff0c;在程序中判斷a是奇數還是偶數&#xff0c;然后輸出判斷的結果。 package 判斷奇偶; public class liux { public static void main(String[] args){ int x5; if(x%20){ System.out.println("這…

推薦一款作圖工具

以前看到別人的時序圖覺得好好看&#xff0c;然后就想這都是用的什么工具畫出來的呢&#xff1f;然后看到了一個師兄用的這個工具&#xff0c;真的挺好用的。這是是試用版的界面。類圖我覺著看起來效果都挺不錯的。轉載于:https://www.cnblogs.com/tuhooo/p/8874410.html

【codeforces】【比賽題解】#849 CF Round #431 (Div.2)

cf的比賽越來越有難度了……至少我做起來是這樣。 先看看題目吧&#xff1a;點我。 這次比賽是北京時間21:35開始的&#xff0c;算是比較良心。 【A】奇數與結束 "奇數從哪里開始&#xff0c;又在哪里結束&#xff1f;夢想從何處起航&#xff0c;它們又是否會破滅呢&#…