天天看點

VOC格式資料集操作類建構-4.resize資料集圖像并修改标注資訊

總目标:建立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)