(圖片來源:digitalinformationworld)
在深度學習建立自己的模型中,收集訓練資料向來是費時的一個大工程,其中,將網路上的 dataset 或是 database 下載下來的訓練資料進行 annotation 的格式轉換也成了無法避免的過程,所以筆者要分享的就是透過 python 建立 VOC dataset annotation 的 XML 檔
筆者在建立之前,前置作業的流程如下 :
Matlab 讀取 Dataset A 的 annotation(.m) → 找出需要的屬性值並輸出成 txt → 讀取 txt 並使用 python 建立 XML (即本文主題)
下圖是筆者想做出的 VOC dataset annotation 格式(裡面的屬性意義,請自行下載 documentation 瞭解) :
轉成樹狀圖如下,建立 xml 就跟建立樹狀圖或是 data structure 的 tree 一樣,定義節點間的父子關係,一層層的建立起來
首先,import xml.dom.minidom 以使用所需函式
關鍵 function : createElement, createTextNode, appendChild
- 使用 createElement 來建立tag
- 使用 createTextNode 來填入 tag 中的 string內容
- 使用 appendchild 來建立上下(父子)結構
<annotation>
<folder>Bal Laedi</folder>
<annotation>
code 就會如下圖所示 :
import xml.dom.minidom #建立空的樹狀圖,可以想像成初始化XML doc = xml.dom.minidom.Document() #建立annotation tag root = doc.createElement('annotation') #將annotation tag放入樹狀圖中 doc.appendChild(root) #建立folder tag folderElem = doc.createElement('folder') #建立folder tag中寫入內容Bal Laedi folderElem.appendChild(doc.createTextNode('Bal Laedi')) #將folder tag設定為annotation的下層 root.appendChild(folderElem)
接下來就差寫入檔案,writexml 除了指定寫入的檔案,還能設定縮排的方式 :
f = open('output.xml', 'w') doc.writexml(f, indent='\t', addindent='\t', newl= '\n')
最後,完整的 code 如下 :
- 以下的 function 除了 filename, size, bndbox 之外,其他的屬性值都是寫死的
- 這裡的 argument txtfile 是用作讀取 txt 檔案中記錄的 xmin, ymin, xmax, ymax 值
def txtToXML(txtfile,imgpath,xmlpath):
doc = xml.dom.minidom.Document()
root = doc.createElement('annotation')
doc.appendChild(root)
folderElem = doc.createElement('folder')
folderElem.appendChild(doc.createTextNode('newImage'))
root.appendChild(folderElem)
filenameElem = doc.createElement('filename')
tmp = files.split('.',1)
imgfilename = tmp[0] + ".jpg"
filenameElem.appendChild(doc.createTextNode(imgfilename))
root.appendChild(filenameElem)
imgpth = imgpath + imgfilename
path = doc.createElement('path')
path.appendChild(doc.createTextNode(imgpth))
root.appendChild(path)
src = doc.createElement('source')
db = doc.createElement('database')
db.appendChild(doc.createTextNode('Unknown'))
src.appendChild(db)
root.appendChild(src)
size = doc.createElement('size')
width = doc.createElement('width')
height = doc.createElement('height')
depth = doc.createElement('depth')
img = cv2.imread(imgpth)
width.appendChild(doc.createTextNode(str(img.shape[1])))
height.appendChild(doc.createTextNode(str(img.shape[0])))
depth.appendChild(doc.createTextNode(str(img.shape[2])))
size.appendChild(width);size.appendChild(height);size.appendChild(depth);
root.appendChild(size)
seg = doc.createElement('segmented')
seg.appendChild(doc.createTextNode('0'))
root.appendChild(seg)
f = open(txtFolder + txtfile,'r')
s = f.readline()
obj = doc.createElement('object')
name = doc.createElement('name')
name.appendChild(doc.createTextNode('hand'))
pose = doc.createElement('pose')
pose.appendChild(doc.createTextNode('Unspecified'))
truncated = doc.createElement('truncated')
truncated.appendChild(doc.createTextNode('0'))
difficult = doc.createElement('difficult')
difficult.appendChild(doc.createTextNode('0'))
obj.appendChild(name);obj.appendChild(pose);obj.appendChild(truncated);obj.appendChild(difficult);
root.appendChild(obj)
xy = s.split(' ',3)
xmin = doc.createElement('xmin')
xmin.appendChild(doc.createTextNode(xy[1]))
ymin = doc.createElement('ymin')
ymin.appendChild(doc.createTextNode(xy[3]))
xmax = doc.createElement('xmax')
xmax.appendChild(doc.createTextNode(xy[0]))
ymax = doc.createElement('ymax')
ymax.appendChild(doc.createTextNode(xy[2]))
bndbox = doc.createElement('bndbox')
bndbox.appendChild(xmin);bndbox.appendChild(ymin);bndbox.appendChild(xmax);bndbox.appendChild(ymax);
obj.appendChild(bndbox)
s = f.readline()
f.close()
f = open(xmlpath, 'w');
doc.writexml(f, indent='\t', addindent='\t', newl= '\n')
f.close()
張貼留言