zoukankan      html  css  js  c++  java
  • Image Processing 必备(五):Imgaug之增强标记BoundingBox

    Date: 2020-09-04

    官方教程:https://nbviewer.jupyter.org/github/aleju/imgaug-doc/blob/master/notebooks/B02%20-%20Augment%20Bounding%20Boxes.ipynb

    通过关键点Keypoints中两个API的学习,对应于BBox,其应该也会存在两个API,一个用于生成BBox,另一个整合BBox。

    事实上,开发人员也是这样设计的:

    • BoundingBox

    • BoundingBoxesOnImage

    不知道之后其他的标记是不是也是这样!

    BBox

    对于BBox,通常用于目标检测中对物体进行标记,此处为矩形。因此,其通过左上角点和右下角点的坐标表示(x1,y1,x2,y2)。

    与关键点Keypoints一致,其只受改变图像几何外观的图像增强技术的影响,高斯噪声之类的对其没有影响。

    API: BoundingBox

    BBox的输入参数:

    imgaug.augmentables.bbs.BoundingBox(x1, y1, x2, y2, label=None):

    可以看到,包含5个输入,4个坐标和1个物体类别标签label。

    BoundingBox有一些重要的属性:.x1, .y1, .x2, .y2, .height, .width, .center_x, .center_y, .area

    BBox的一些方法:

    • project(from_shape, to_shape) : 投射一个bbox从一个尺寸大小的图像到另一个尺寸大小。

    • *extend([all_sides], [top], [right], [bottom], [left]) *

    • *intersection(other, [default]) * :交集

    • *union(other) * :并集

    • *iou(other) * : 交并比

    • *is_fully_within_image(image) * 判断所有的bbox是否都在图像内

    • *is_partly_within_image(image) * 确定bbox至少有一部分在图像内

    • *clip_out_of_image(image) * :剪切掉在图像外侧的BBox

    • *shift([x], [y]) * : 移动bbox

    • *draw_on_image(image, [color], [alpha], [size], [copy], [raise_if_out_of_image]) *:绘制BBox和它的label

    • *draw_label_on_image(image, [color], [color_text], [color_bg], [alpha], [size], [size_text], [height], [copy], [raise_if_out_of_image]) * :只绘制label

    • *draw_box_on_image(image, [color], [alpha], [size], [copy], [raise_if_out_of_image) * :只绘制边框

    • *extract_from_image(image, [pad], [pad_max], [prevent_zero_size] *:从图像中提取边框中包含的像素

    API:BoundingBoxesOnImage

    BoundingBoxesOnImage()输入参数:

    imgaug.augmentables.bbs.BoundingBoxesOnImage(bounding_boxes, shape)

    BoundingBoxesOnImage中包含的一些方法:

    • on(image): 图形变化后bbox的再计算

    • *from_xyxy_array(xyxy, shape) *: 通过(N, 4)numpy数组生成

    • *to_xyxy_array([dtype]) *: 生成(N, 4)的numpy数组

    • *draw_on_image([color], [alpha], [size], [copy], [raise_if_out_of_image]) *:绘制bbox和image

    • *remove_out_of_image([fully], [partly]) *: 移除掉一些完全不在或者部分不在图像中的bbox

    • *clip_out_of_image() *: 剪切掉所有的bbox

    • *shift([x], [y]) *:平移所有的bbox

    另外,imgaug中还有一些其他的API,例如增强BBOx和图像aug.augment(images=..., bounding_boxes=...) && aug.augment_bounding_boxes()

    Example

    绘制bbox

    1 import imgaug as ia
    2 import imageio
    3 from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
    4 %matplotlib inline
    5 ia.seed(1)
    6 img = imageio.imread("samoye.jpg")
    7 bbs = BoundingBoxesOnImage([
    8     BoundingBox(x1=65, y1=1, x2=417, y2=396)], shape=img.shape)
    9 ia.imshow(bbs.draw_on_image(img, size=2))

    png

    对图像使用增强方法后绘制

    仿射变换

     1 # 定义方法
     2 from imgaug import augmenters as iaa
     3 ia.seed(1)
     4  5 seq = iaa.Sequential([iaa.GammaContrast(1.5),
     6                      iaa.Affine(translate_percent={"x":0.1}, scale=0.8)])
     7  8 # 作用于图像和bbox上
     9 image_aug, bbs_aug = seq(image=img, bounding_boxes=bbs)
    10 # 绘制
    11 ia.imshow(bbs_aug.draw_on_image(image_aug, size=2))

    png

    旋转45°包含的问题
    1 image_aug, bbs_aug = iaa.Affine(rotate=45)(image=img, bounding_boxes=bbs)
    2 ia.imshow(bbs_aug.draw_on_image(image_aug, size=1))

    png

    官方教程中使用的图像旋转后可以看到bbox,但bbox并未很好的跟随目标进行旋转。这里使用的图像旋转后,并不能看到bbox。官方教程中解释说这种问题源于非目标像素是边框的一部分。在旋转之后,必须绘制一个新的边界框来合并这些非对象像素。

    绘制

    和关键点一致,bbox的draw_on_image()方法同样可以通过color、size、alpha等参数调节bbox的颜色 粗细 透明度。

    1 import numpy as np
    2 image_bbs = np.copy(img)
    3 image_bbs = bbs.draw_on_image(img, color=[255, 0, 0], size=3)
    4 print("color=[255,0,0],size=3,")
    5 ia.imshow(image_bbs)
    6 print("color=[0,255,0],size=10,alpha=0.5")
    7 image_bbs_1=bbs.draw_on_image(img, color=[0,255,0],size=10,alpha=0.5)
    8 ia.imshow(image_bbs_1)
    color=[255,0,0],size=3,

    png

    color=[0,255,0],size=10,alpha=0.5

    png

    从中又可以看出,当size较大时,靠近边缘的bbox边界有可能绘制不出。

    另外,bbox通常用于目标检测,需要添加目标的label进行可视化。bbox中还包含label的字段。当bbox初始化时包含了label,显示时就会直接显示label;若初始化时未赋值label,则需要赋值才可以显示。

    1 bbs_label = bbs.deepcopy()
    2 bbs_label[0].label = "dog"
    3 4 image_bbs = bbs_label.draw_on_image(img, size=1)
    5 ia.imshow(image_bbs)

    png

    但由于上边框贴近图像边缘,label并未绘制显示。

    换一张图像...

    1 image = imageio.imread("fox.jpg")
    2 
    3 bbox = BoundingBoxesOnImage([BoundingBox(x1=58, y1=19, x2=203, y2=183)
    4                             ], shape=image.shape)
    5 bbox[0].label = "fox"
    6 image_bbox = bbox.draw_on_image(image, size=2)
    7 ia.imshow(image_bbox)

    png

    提取目标区域

    BoundingBox包含extract_from_image(image)方法,可以提取出目标区域的图像。

    1 fox = bbox.bounding_boxes[0].extract_from_image(image)
    2 ia.imshow(fox)

    png

    如果想要提取到目标及目标周边的一些区域,可以结合使用extend方法,先将bbox进行延伸,再提取延伸后的bbox区域的图像。

    1 fox = bbox.bounding_boxes[0].extend(
    2     all_sides=0, left=30, right=10).extract_from_image(image)
    3 ia.imshow(fox)

    png

    除了extend方法,shift方法可以对bbox进行移动,就像Keypoints。

    1 bb = bbox.bounding_boxes[0].shift(x=20, y=20)
    2 ia.imshow(bb.draw_on_image(image, size=2))
    3 ia.imshow(bb.extract_from_image(image))

    png

    png

    综上所述,extend可以更改bbox的形状,可以扩张或者缩小bbox;而shift只能对bbox进行平移,不会影响bbox的尺寸。

    同时,当对原有的bbox往y轴方向移动20个像素点,bbox将会处于图像外界。如上述第二张图像,会有一溜黑边。当然,如果不希望出现这种情况,可以增加参数pad=False,如下述图所示,生成的图像将不会有黑边。

    1 bb = bbox.bounding_boxes[0].shift(x=20, y=20)
    2 ia.imshow(bb.extract_from_image(image, pad=False))

    png

    裁剪bbox

    当图像经过变换后,对应的bbox有可能部分处于图像的外侧,剪掉图像平面外的边界框的部分可以使用.clip_out_of_image(<image or shape tuple>)方法。下述代码首先将bbox移动到部分处于图像外侧,并对bbox进行裁剪。

     1 print("-------------------")
     2 print("shifted by 50 px - y")
     3 print("-------------------")
     4 bb = bbox.bounding_boxes[0].shift(y=50)
     5 print("before clip")
     6 ia.imshow(bb.draw_on_image(image, size=2))
     7 ia.imshow(bb.extract_from_image(image))
     8 bb_clip =bb.clip_out_of_image(image.shape)
     9 print("after clip")
    10 ia.imshow(bb_clip.draw_on_image(image, size=2))
    11 ia.imshow(bb_clip.extract_from_image(image))
    -------------------
    shifted by 50 px - y
    -------------------
    before clip

    png

    png

    after clip

    png

    png

    可以看出,当剪切掉图像外侧的bbox后,在原图中显示的bbox可以很好的显示边界。

    将bbox投射到其他图像上

    与Keypoints相同,bbox也具有应对图像缩放后保持bbox一致的方法:

    • project

    • on

     1 import numpy as np
     2 import imageio
     3 import imgaug as ia
     4 from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
     5 from imgaug import augmenters as iaa 
     6 %matplotlib inline
     7 img = imageio.imread("koala.jpg")
     8 
     9 bbox = BoundingBoxesOnImage([BoundingBox(x1=26, y1=8, x2=109, y2=160)
    10                             , BoundingBox(x1=39, y1=4, x2=245, y2=194)], shape=img.shape)
    11 bbox[0].label = "koala"
    12 bbox[1].label = "koala"
    13 ia.imshow(bbox.draw_on_image(img, size=2))
    14 print(img.shape)

    png

    (194, 259, 3)

    将图像缩放到120*120

    1 img_resize = ia.imresize_single_image(img, (120, 120))
    2 ia.imshow(img_resize)

    png

    1 print("Bounding box without changes:")
    2 ia.imshow(bbox.draw_on_image(img_resize, size=2))
    3 
    4 print("Bounding box with project(from, to)")  # 需要对bbox中的Boundingbox进行处理
    5 ia.imshow(bbox.bounding_boxes[0].project(from_shape=img.shape, to_shape=img_resize.shape).draw_on_image(img_resize, size=2, copy=False))
    6 ia.imshow(bbox.bounding_boxes[1].project(from_shape=img.shape, to_shape=img_resize.shape).draw_on_image(img_resize, size=2, copy=False))
    7 
    8 print("Bounding box with on(shape)")   # 可以对整个bbox进行处理
    9 ia.imshow(bbox.on(img_resize.shape).draw_on_image(img_resize, color=(255,255,0), size=2))
    Bounding box without changes:

    png

    Bounding box with project(from, to)

    png

    png

    Bounding box with on(shape)

    png

    交集、并集、交并比

    bbox之间通常会计算IoU,imgaug中提供了相应的方法:

    • BoundingBox.intersection(other_bounding_box)

    • BoundingBox.union(other_bounding_box)

    • BoundingBox.iou(other_bounding_box)

    intersection

    1 bb_intersection = bbox.bounding_boxes[0].intersection(bbox.bounding_boxes[1])
    2 ia.imshow(bb_intersection.draw_on_image(img, size=2))

    png

    如上图所示,返回的bb_intersection实际上是两个bbox交集的bbox。

    同时,可以通过bb_intersection获取到交集的高度、宽度、面积等信息。

    1 print("The intersection has a height of %.4f, width of %.4f and an area of %.4f"%(
    2 bb_intersection.height, bb_intersection.width, bb_intersection.area))
    The intersection has a height of 152.0000, width of 70.0000 and an area of 10640.0000

    union

    1 bb_union = bbox.bounding_boxes[0].union(bbox.bounding_boxes[1])
    2 ia.imshow(bb_union.draw_on_image(img, size=2))

    png

    如上图所示,返回的bb_union实际上是两个bbox并集的bbox。

    同理,可以通过bb_bb_union获取到交集的高度、宽度、面积等信息。

    1 print("The union has a height of %.4f, width of %.4f and an area of %.4f"%(
    2 bb_union.height, bb_union.width, bb_union.area))
    The union has a height of 190.0000, width of 219.0000 and an area of 41610.0000

    IoU

    1 iou = bbox.bounding_boxes[0].iou(bbox.bounding_boxes[1])
    2 print("IoU: %.4f"%(iou))
    IoU: 0.2588

     整理总结

    本节主要介绍了imgaug中BoundingBox和BoundingBoxesOnImage两个API,以及API中包含的方法。

  • 相关阅读:
    Docker跨平台架构的新特性buildx的启用方式
    Linux 如何安装rvm和ruby
    Linux
    ubuntu安装 vmware workstation pro 15.1.1
    docker-compose搭建golang本地开发环境
    linux 常用命令
    leetcode 1046 最后一块石头的重量
    leetcode 330 按要求补齐数组
    MySQL 字符集与比较规则
    Python 是什么语言
  • 原文地址:https://www.cnblogs.com/monologuesmw/p/13691536.html
Copyright © 2011-2022 走看看