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中包含的方法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM