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