1. 程式人生 > >【學習筆記】使用python批量讀取並修改xml檔案(2)

【學習筆記】使用python批量讀取並修改xml檔案(2)

在大老闆的安排下最近在某公司實習,實習期間要求實現一個影象識別模組的封裝。無奈基礎太薄弱,只能將任務細分,單獨學習來實現。以此為背景……


這一篇記錄一些在實際使用中踩到的。在實際使用中,我在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型資料,因此會在取整時產生誤差。誤差大概如下圖所示:

感覺還能接受……但是還是希望看到的大神指點一下,謝謝!