總目标:建立VOC格式資料集類以及操作函數庫
VOC類庫存儲在VOC.py中,單個xml檔案操作函數庫存儲在VOCOperationLibrary.py
VOC類import VOCOperationLibrary as vol
github項目位址(附有使用說明書):
https://github.com/A-mockingbird/VOCtype-datasetOperation
Day4.resize資料集圖像并修改标注資訊
内容:
對資料集的所有圖像進行熱死則,修改尺寸,并修改标注資訊,使标注位置準确。
1.Resize方法
輸入參數:
newsize:元組,resize後的尺寸,(寬,高),例如(512, 512)
annodir:标注xml檔案目錄
imgdir:圖像檔案目錄
内容:
先擷取資料集全部圖像檔案名和對應标注檔案名,
周遊全部圖像檔案,修改其尺寸并儲存(覆寫原圖像檔案)
周遊标注資訊xml檔案,修改尺寸資訊和位置資訊
def _Resize(self, newsize, annodir=None, imgdir=None):
if annodir == None:
annodir = self.dataset_anno
if imgdir == None:
imgdir = self.dataset_img
if imgdir == None:
print('Resize operation need a image direction!')
return
#擷取全部标注檔案和圖像檔案
annolist = self._listanno(annodir)
imglist = self._listimg(imgdir)
annos = self._ParseAnnos(annodir)
total = len(annolist)
#對全部标注檔案名周遊
for num, f in enumerate(annolist):
#标注檔案和圖像檔案路徑,os.path.join(a,b)合并a,b路徑
anno_path = os.path.join(annodir, f)
img_path = os.path.join(imgdir, f)[:-4] + '.jpg'
#使用PIL子產品打開圖檔
img = Image.open(img_path)
#resize圖檔,newsize是一個元組(tuple),(寬, 高)
img = img.resize(newsize)
#儲存圖像,quality是儲存圖像品質
img.save(img_path, 'jpeg', quality=95)
img.close()
#對圖像标注資訊進行修改,之後會說明vol.changeone()函數
vol._changeone(anno_path, None, None, newsize)
#顯示進度條
process = int(num*100 / total)
s1 = "\r%d%%[%s%s]"%(process,"*"*process," "*(100-process))
s2 = "\r%d%%[%s]"%(100,"*"*100)
sys.stdout.write(s1)
sys.stdout.flush()
sys.stdout.write(s2)
sys.stdout.flush()
print('')
print('Resize is complete!')
2.修改标注資訊,圖像尺寸和目标位置
def _changeone(annofile, oldcls, newcls, newsize=None):
if os.path.exists(annofile) == False:
raise FileNotFoundError
#擷取xml檔案根節點
tree = ET.parse(annofile)
root = tree.getroot()
#擷取全部子節點,為防止寫入修改資訊後節點改變
annos = [anno for anno in root.iter()]
for i, anno in enumerate(annos):
#修改xml檔案中圖像尺寸資訊
#計算x軸,y軸位置變化率
if newsize != None:
if 'width' in anno.tag:
oldwidth = float(anno.text)
anno.text = str(newsize[0])
sizechangerate_x = newsize[0] / oldwidth
if 'height' in anno.tag:
oldheight = float(anno.text)
anno.text = str(newsize[1])
sizechangerate_y = newsize[1] / oldheight
if 'object' in anno.tag:
for element in list(anno):
#這是之前教程中修改類别名用到的,
#此處oldcls和newcls均輸入為同一個值即可,例如均為None
if oldcls != newcls:
if 'name' in element.tag:
if element.text == oldcls:
element.text = newcls
print(os.path.basename(annofile)+' change the class name')
break
#修改位置資訊
if newsize != None:
if 'bndbox' in element.tag:
for coordinate in list(element):
if 'xmin' in coordinate.tag:
coordinate.text = str(int(int(coordinate.text) * sizechangerate_x))
if 'xmax' in coordinate.tag:
coordinate.text = str(int(int(coordinate.text) * sizechangerate_x))
if 'ymin' in coordinate.tag:
coordinate.text = str(int(int(coordinate.text) * sizechangerate_y))
if 'ymax' in coordinate.tag:
coordinate.text = str(int(int(coordinate.text) * sizechangerate_y))
#寫入修改資訊,覆寫原xml檔案
tree = ET.ElementTree(root)
tree.write(annofile, encoding="utf-8", xml_declaration=True)