[深度学习] imgaug边界框增强笔记

imgaug边界框增强笔记主要是讲述基于imgaug库对目标检测图像的边界框进行图像增强。本文需要掌握imgaug库的基本使用,imgaug库的基本使用见[深度学习] imgaug库使用笔记

0 示例图像和标注文件

示例图像如图所示
demo

# 对应的标注文件
!cat demo.xml
<?xml version="1.0" ?>
<annotation>
<folder>demo</folder>
<filename>demo.jpg</filename>
<path>demo.jpg</path>
<source>
    <database>Unknown</database>
</source>
<size>
    <width>640</width>
    <height>424</height>
    <depth>3</depth>
</size>

<segmented>0</segmented>
    <object>
    <name>person</name>
    <pose>Unspecified</pose>
    <truncated>0</truncated>
    <difficult>0</difficult>
    <bndbox>
        <xmin>187</xmin>
        <ymin>93</ymin>
        <xmax>276</xmax>
        <ymax>378</ymax>
    </bndbox>
</object>
    <object>
    <name>horse</name>
    <pose>Unspecified</pose>
    <truncated>0</truncated>
    <difficult>0</difficult>
    <bndbox>
        <xmin>390</xmin>
        <ymin>138</ymin>
        <xmax>602</xmax>
        <ymax>345</ymax>
    </bndbox>
</object>
    <object>
    <name>dog</name>
    <pose>Unspecified</pose>
    <truncated>0</truncated>
    <difficult>0</difficult>
    <bndbox>
        <xmin>61</xmin>
        <ymin>256</ymin>
        <xmax>207</xmax>
        <ymax>348</ymax>
    </bndbox>
</object>
</annotation>

1 imgaug加载图像和标注数据

标注文件的数据信息需要从外部读取后放入imgaug的BoundingBox类中,本文标注文件的数据信息通过BeautifulSoup读取。BeautifulSoup学习文章见使用 Beautiful Soup。具体代码如下。

from bs4 import BeautifulSoup
import imgaug as ia
import imageio
from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
from imgaug import augmenters as iaa 

# 打开标注文件
soup = BeautifulSoup(open('demo.xml'),"lxml")
# 导入图像
image = imageio.imread("demo.jpg")


# 用于存放标注文件边界框信息
bbsOnImg=[]
# 找到所有包含框选目标的节点
for objects in soup.find_all(name="object"):
    # 获得当前边界框的分类名
    object_name = str(objects.find(name="name").string)
    # 提取坐标点信息
    xmin = int(objects.xmin.string)
    ymin = int(objects.ymin.string)
    xmax = int(objects.xmax.string)
    ymax = int(objects.ymax.string)
    # 保存该边界框的信息
    bbsOnImg.append(BoundingBox(x1=xmin, x2=xmax, y1=ymin, y2=ymax,label=object_name))
# 初始化imgaug的标选框数据
bbs = BoundingBoxesOnImage( bbsOnImg,shape=image.shape)
# 展示结果
ia.imshow(bbs.draw_on_image(image, size=2))

png

2 边界框增强

imgaug中的边界框增强有两种办法,一种是对整张图像增强,另外一种是根据边界框信息,图像部分区域增强。

2.1 整张图像增强

直接对整张图像进行增强,直接从imgaug增强效果示例中找示例代码,然后添加到iaa.Sequential()中叠加就可以实现图像增强。

# 增强效果
seq = iaa.Sequential([
    iaa.GammaContrast(1.5),
    iaa.Fliplr(1),
    iaa.Cutout(fill_mode="constant", cval=255),
    iaa.CoarseDropout(0.02, size_percent=0.15, per_channel=0.5),
])

# 输入增强前的图像和边框,得到增强后的图像和边框
image_aug, bbs_aug = seq(image=image, bounding_boxes=bbs)
# 可视化,size边框的宽度
ia.imshow(bbs_aug.draw_on_image(image_aug, size=2))

png

2.2 图像部分区域增强

imgaug可以只对边界框框选区域或者除边界框的区域进行图像增强,通过imgaug的BlendAlphaBoundingBoxes类实现。BlendAlphaBoundingBoxes类的接口说明如下:

classimgaug.augmenters.blend.BlendAlphaBoundingBoxes(labels, foreground=None, background=None, nb_sample_labels=None, seed=None, name=None, random_state='deprecated', deterministic='deprecated')

该类的常用参数为labels,foreground,background。labels表示对哪一类或哪几类的边界框进行处理,为None表示所有标签都处理。foreground设置对labels标注的边界框区域增强效果。background设置对除边界库区域增强效果。示例代码如下:

# demo1
seq = iaa.Sequential([
    # background设置除了dog和person标选框之外的区域都涂黑
    iaa.BlendAlphaBoundingBoxes(['dog','person'],background=iaa.Multiply(0.0)),
    # 对整张图进行增强
    #iaa.Cartoon()
])
# 输入增强前的图像和边框,得到增强后的图像和边框
image_aug, bbs_aug = seq(image=image, bounding_boxes=bbs)
# 可视化,size边框的宽度
ia.imshow(bbs_aug.draw_on_image(image_aug, size=2))

png

# demo2
seq = iaa.Sequential([
    # label=None表示不选择特定标签,即对所以标签进行处理
    iaa.BlendAlphaBoundingBoxes(None,foreground=iaa.Fog())
])
# 输入增强前的图像和边框,得到增强后的图像和边框
image_aug, bbs_aug = seq(image=image, bounding_boxes=bbs)
# 可视化,size边框的宽度
ia.imshow(bbs_aug.draw_on_image(image_aug, size=2))

png

# demo3
seq = iaa.Sequential([
    # 前后景分别处理
    iaa.BlendAlphaBoundingBoxes(["dog","person"],foreground=iaa.Fog(),background=iaa.Cartoon()),
    # 整张图片增强效果
    iaa.Fliplr(1)
])
# 输入增强前的图像和边框,得到增强后的图像和边框
image_aug, bbs_aug = seq(image=image, bounding_boxes=bbs)
# 可视化,size边框的宽度
ia.imshow(bbs_aug.draw_on_image(image_aug, size=2))

png

2.3 边界框超出图像范围解决办法

[深度学习] imgaug库使用笔记中有提到不要图像旋转来增强边界框,很容易出现边界框超出图像范围,在imgaug中也提供了相应的解决办法, 通过clip_out_of_image函数即可解决。尽管这样,还是不建议使用图像旋转增强边界框。

seq = iaa.Sequential([
    iaa.Affine(rotate=80)
])


# 输入增强前的图像和边框,得到增强后的图像和边框
image_aug, bbs_aug = seq(image=image, bounding_boxes=bbs)
# 可视化,size边框的宽度
ia.imshow(bbs_aug.draw_on_image(image_aug, size=2))
# 显示边界框结果,可以看到dog和horse的边界框范围超过图像。
bbs_aug

png

BoundingBoxesOnImage([BoundingBox(x1=133.4267, y1=60.3564, x2=429.5516, y2=197.4940, label=person), BoundingBox(x1=201.1759, y1=268.0866, x2=441.8446, y2=512.8110, label=horse), BoundingBox(x1=141.0913, y1=-35.4247, x2=257.0462, y2=124.3329, label=dog)], shape=(424, 640, 3))
# 删除超过图像范围的边界框范围
bbs_aug_clip =bbs_aug.clip_out_of_image()
# 可视化
ia.imshow(bbs_aug_clip.draw_on_image(image_aug, size=2))
bbs_aug_clip

png

BoundingBoxesOnImage([BoundingBox(x1=133.4267, y1=60.3564, x2=429.5516, y2=197.4940, label=person), BoundingBox(x1=201.1759, y1=268.0866, x2=441.8446, y2=424.0000, label=horse), BoundingBox(x1=141.0913, y1=0.0000, x2=257.0462, y2=124.3329, label=dog)], shape=(424, 640, 3))

3 保存增强图像和标注文件

xml标注文件保存参考python如何读取&生成voc xml格式标注信息。可自行修改相关代码。本文保存代码如下。

# xml文件生成代码
from lxml import etree

# ---- 创建标注
class CreateAnnotations:
    # ----- 初始化
    def __init__(self, flodername, filename):
        self.root = etree.Element("annotation")

        child1 = etree.SubElement(self.root, "folder")
        child1.text = flodername

        child2 = etree.SubElement(self.root, "filename")
        child2.text = filename

        child3 = etree.SubElement(self.root, "path")
        child3.text = filename

        child4 = etree.SubElement(self.root, "source")

        child5 = etree.SubElement(child4, "database")
        child5.text = "Unknown"

    # ----- 设置size
    def set_size(self, imgshape):
        (height, witdh, channel) = imgshape
        size = etree.SubElement(self.root, "size")
        widthn = etree.SubElement(size, "width")
        widthn.text = str(witdh)
        heightn = etree.SubElement(size, "height")
        heightn.text = str(height)
        channeln = etree.SubElement(size, "depth")
        channeln.text = str(channel)

    # ----- 保存文件
    def savefile(self, filename):
        tree = etree.ElementTree(self.root)
        tree.write(filename, pretty_print=True, xml_declaration=False, encoding='utf-8')

    def add_pic_attr(self, label, xmin, ymin, xmax, ymax):
        object = etree.SubElement(self.root, "object")
        namen = etree.SubElement(object, "name")
        namen.text = label
        bndbox = etree.SubElement(object, "bndbox")
        xminn = etree.SubElement(bndbox, "xmin")
        xminn.text = str(xmin)
        yminn = etree.SubElement(bndbox, "ymin")
        yminn.text = str(ymin)
        xmaxn = etree.SubElement(bndbox, "xmax")
        xmaxn.text = str(xmax)
        ymaxn = etree.SubElement(bndbox, "ymax")
        ymaxn.text = str(ymax)
# 从imgaug中提取边界框信息并保存

foldername = "demo"
filename = "demo_aug.jpg"

# 创建保存类
anno = CreateAnnotations(foldername, filename)
# 
anno.set_size(image_aug.shape)
# 循环提取
for index,bb in enumerate(bbs_aug_clip):
    xmin = int(bb.x1)
    ymin = int(bb.y1)
    xmax = int(bb.x2)
    ymax = int(bb.y2)
    label = str(bb.label)
    anno.add_pic_attr(label, xmin, ymin, xmax, ymax)
# 保存标注文件
anno.savefile("{}.xml".format(filename.split(".")[0]))
# 保存增强图像
imageio.imsave(filename, image_aug)

4 参考

posted @ 2021-02-02 19:26  落痕的寒假  阅读(114)  评论(0编辑  收藏  举报