通過關鍵點Keypoints中兩個API的學習,對應於BBox,其應該也會存在兩個API,一個用於生成BBox,另一個整合BBox。
事實上,開發人員也是這樣設計的:
-
-
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))
對圖像使用增強方法后繪制
仿射變換
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))
旋轉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))
官方教程中使用的圖像旋轉后可以看到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,
color=[0,255,0],size=10,alpha=0.5
從中又可以看出,當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)
但由於上邊框貼近圖像邊緣,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)
提取目標區域
BoundingBox包含extract_from_image(image)方法,可以提取出目標區域的圖像。
1 fox = bbox.bounding_boxes[0].extract_from_image(image) 2 ia.imshow(fox)
如果想要提取到目標及目標周邊的一些區域,可以結合使用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)
除了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))
綜上所述,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))
裁剪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
after clip
可以看出,當剪切掉圖像外側的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)
(194, 259, 3)
將圖像縮放到120*120
1 img_resize = ia.imresize_single_image(img, (120, 120)) 2 ia.imshow(img_resize)
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:
Bounding box with project(from, to)
Bounding box with on(shape)
交集、並集、交並比
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))
如上圖所示,返回的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))
如上圖所示,返回的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中包含的方法。