【學習筆記】使用python批量讀取並修改xml檔案(2)
阿新 • • 發佈:2019-01-02
在大老闆的安排下最近在某公司實習,實習期間要求實現一個影象識別模組的封裝。無奈基礎太薄弱,只能將任務細分,單獨學習來實現。以此為背景……
這一篇記錄一些在實際使用中踩到的坑。在實際使用中,我在A資料夾下對圖片進行了標註,隨後將圖片移動到B資料夾下。那麼相應的,標註後的xml檔案中,<path>標籤的值就應該修改。
最初的思路是,我遍歷了xml檔案,那麼我只需要將‘新地址’+xml檔案寫入到新的<path>中即可。
paths[i].firstChild.data='/home/kanghao/SSD-Tensorflow/yibiao512/JPEGImages/'+xmlFile
即這一句程式碼,使用後發現自己腦子抽了……<path>中的標籤值為:
<path>/home/kanghao/learning_something/about_xml/yibiao512/img/a0000000.jpg</path>
重點是後面跟隨的是圖片的副檔名。
於是想到是否可以再次遍歷圖片資料夾,獲取圖片資訊之後再與新地址相連?在實際操作中不知如何同時遍歷兩個資料夾……_(°:з」∠)_禿頭
於是採取小黃鴨debug方法,在與小夥伴講解訴求的過程中猛然發現,我要獲取的不就是<filename>標籤的值嗎?獲取了這個值之後,新增的新地址後面就好了呀。於是按照這個思路,完整程式碼如下:
#coding:utf-8 ### V1.0版 ### 針對xml檔案,要修改的地方是<folder><path><width><height><bndbox> ### 程式瑕疵,在計算bud box時使用float格式,openCV畫框函式為int格式 ### 因此會產生誤差 import os import os.path import xml.dom.minidom #path="../xml/" path='/home/kanghao/SSD-Tensorflow/yibiao512/Annotations/' files=os.listdir(path) #得到資料夾下所有檔名稱 for xmlFile in files: #遍歷資料夾 if not os.path.isdir(xmlFile): #判斷是否是資料夾,不是資料夾才打開 print xmlFile #xml讀取操作 #將獲取到的xml檔名送入到dom解析 #錯誤程式碼:dom=xml.dom.minidom.parse(xmlFile) dom=xml.dom.minidom.parse(os.path.join(path,xmlFile)) root=dom.documentElement ###獲取標籤對xmin/ymin之間的值 # ~ folder=root.getElementsByTagName('folder') paths=root.getElementsByTagName('path') filenames=root.getElementsByTagName('filename') # ~ xmin=root.getElementsByTagName('xmin') # ~ ymin=root.getElementsByTagName('ymin') # ~ #修改相應標籤的值 # ~ # 修改<folder> # ~ for i in range(len(folder)): # ~ print folder[i].firstChild.data # ~ folder[i].firstChild.data='xml' # ~ print folder[i].firstChild.data for i in range(len(filenames)): fn = filenames[i].firstChild.data ############################################################################################################### ### 如何修改path?每個xml檔案對應不同名字的圖片??? ### 解決方式如下,測試成功×----------->開始的思路有問題, ###paths[i].firstChild.data='/home/kanghao/SSD-Tensorflow/yibiao512/JPEGImages/'+fn語句中,fn使用的是xmlFiles ###那麼修改後的path中字尾加的是xml檔案,不是對應的jpg檔案。 思路2————————>直接讀取filename標籤中的值,新增到地址後即可 ############################################################################################################### # 修改<path> for i in range(len(paths)): print paths[i].firstChild.data paths[i].firstChild.data='/home/kanghao/SSD-Tensorflow/yibiao512/JPEGImages/'+fn print paths[i].firstChild.data # ~ # 修改<xmin> # ~ for k in range(len(xmin)): # ~ print xmin[k].firstChild.data # ~ xia = unicode.encode(xmin[k].firstChild.data) # ~ xmin[k].firstChild.data=float(xia)/1.25 # ~ print xmin[k].firstChild.data # ~ # 修改<ymin> # ~ for j in range(len(ymin)): # ~ print ymin[j].firstChild.data # ~ yia = unicode.encode(ymin[j].firstChild.data) # ~ ymin[j].firstChild.data=float(yia)/1.0666667 # ~ print ymin[j].firstChild.data #儲存修改到xml檔案中 with open(os.path.join(path,xmlFile),'w') as fh: dom.writexml(fh) # ~ with open(os.path.join(path2,jpgFile),'w') as fh: # ~ dom.writexml(fh) print('恭喜,寫入xmin/ymin成功!')
那一大坨註釋,就是為了方便自己理解……_(°:з」∠)_禿頭again。
對了,#coding:utf-8要寫在開頭,編譯器才能以utf-8的各種編譯。
one more thing……
我想用openCV的cv2.rectangle()函式來畫框,驗證我按比例變化是否準確,相關程式碼如下:
#coding:utf-8
import os
import cv2
import numpy as np
import xml.dom.minidom
import pandas as pd
from PIL import Image, ImageDraw, ImageFont
input_file="/home/kanghao/learning_something/about_xml/xml/"
dirs_name=os.listdir("/home/kanghao/learning_something/about_xml/jpg/") #圖片地址
for img in dirs_name:
im=cv2.imread("/home/kanghao/learning_something/about_xml/jpg/"+img) #讀取圖片
dom=xml.dom.minidom.parse(input_file+img[:-4]+".xml") # 讀取圖片對應的label資訊 xml檔案
root=dom.documentElement
objs=root.getElementsByTagName("object")
name=[]
xmin=[]
ymin=[]
xmax=[]
ymax=[]
for obj in objs:
name1=obj.getElementsByTagName('name')
n=name1[0].firstChild.data
xmin1=obj.getElementsByTagName('xmin')
xi=xmin1[0].firstChild.data
ymin1=obj.getElementsByTagName('ymin')
yi=ymin1[0].firstChild.data
xmax1=obj.getElementsByTagName('xmax')
xa=xmax1[0].firstChild.data
ymax1=obj.getElementsByTagName('ymax')
ya=ymax1[0].firstChild.data
xmin.append(float(xi.strip()))
print(xmin)
ymin.append(float(yi.strip()))
xmax.append(float(xa.strip()))
ymax.append(float(ya.strip()))
name.append(n.strip())
for i in range(0,len(xmin)):
#畫box
cv2.rectangle(im, (int(xmin[i]),int(ymin[i])), (int(xmax[i]),int(ymax[i])), (0,255,0), 4)
cv2img = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
pilimg = Image.fromarray(cv2img)
draw = ImageDraw.Draw(pilimg)
# ~ # 寫標註
# ~ for i in range(0,len(xmin)):
# ~ font = ImageFont.truetype("simhei.ttf", 40, encoding="utf-8")
# ~ draw.text((xmin[i], ymin[i]-40), name[i], (255, 0, 0), font=font)
cv2charimg = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)
#儲存圖片
cv2.imwrite("/home/kanghao/learning_something/about_xml/xml/"+img,cv2charimg)
但是問題來了,cv2.rectangle函式中都是int型的資料型別,我在做了除法之後都是float型資料,因此會在取整時產生誤差。誤差大概如下圖所示:
感覺還能接受……但是還是希望看到的大神指點一下,謝謝!