天天看点

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)