yacwc
This commit is contained in:
300
data_aug/bbox_util.py
Normal file
300
data_aug/bbox_util.py
Normal file
@@ -0,0 +1,300 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
|
||||
def draw_rect(im, cords, color = None):
|
||||
"""Draw the rectangle on the image
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
im : numpy.ndarray
|
||||
numpy image
|
||||
|
||||
cords: numpy.ndarray
|
||||
Numpy array containing bounding boxes of shape `N X 4` where N is the
|
||||
number of bounding boxes and the bounding boxes are represented in the
|
||||
format `x1 y1 x2 y2`
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndarray
|
||||
numpy image with bounding boxes drawn on it
|
||||
|
||||
"""
|
||||
|
||||
im = im.copy()
|
||||
|
||||
cords = cords[:,:4]
|
||||
cords = cords.reshape(-1,4)
|
||||
if not color:
|
||||
color = [255,255,255]
|
||||
for cord in cords:
|
||||
|
||||
pt1, pt2 = (cord[0], cord[1]) , (cord[2], cord[3])
|
||||
|
||||
pt1 = int(pt1[0]), int(pt1[1])
|
||||
pt2 = int(pt2[0]), int(pt2[1])
|
||||
|
||||
im = cv2.rectangle(im.copy(), pt1, pt2, color, int(max(im.shape[:2])/200))
|
||||
return im
|
||||
|
||||
def bbox_area(bbox):
|
||||
return (bbox[:,2] - bbox[:,0])*(bbox[:,3] - bbox[:,1])
|
||||
|
||||
def clip_box(bbox, clip_box, alpha):
|
||||
"""Clip the bounding boxes to the borders of an image
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
bbox: numpy.ndarray
|
||||
Numpy array containing bounding boxes of shape `N X 4` where N is the
|
||||
number of bounding boxes and the bounding boxes are represented in the
|
||||
format `x1 y1 x2 y2`
|
||||
|
||||
clip_box: numpy.ndarray
|
||||
An array of shape (4,) specifying the diagonal co-ordinates of the image
|
||||
The coordinates are represented in the format `x1 y1 x2 y2`
|
||||
|
||||
alpha: float
|
||||
If the fraction of a bounding box left in the image after being clipped is
|
||||
less than `alpha` the bounding box is dropped.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndarray
|
||||
Numpy array containing **clipped** bounding boxes of shape `N X 4` where N is the
|
||||
number of bounding boxes left are being clipped and the bounding boxes are represented in the
|
||||
format `x1 y1 x2 y2`
|
||||
|
||||
"""
|
||||
ar_ = (bbox_area(bbox))
|
||||
x_min = np.maximum(bbox[:,0], clip_box[0]).reshape(-1,1)
|
||||
y_min = np.maximum(bbox[:,1], clip_box[1]).reshape(-1,1)
|
||||
x_max = np.minimum(bbox[:,2], clip_box[2]).reshape(-1,1)
|
||||
y_max = np.minimum(bbox[:,3], clip_box[3]).reshape(-1,1)
|
||||
|
||||
bbox = np.hstack((x_min, y_min, x_max, y_max, bbox[:,4:]))
|
||||
|
||||
delta_area = ((ar_ - bbox_area(bbox))/ar_)
|
||||
|
||||
mask = (delta_area < (1 - alpha)).astype(int)
|
||||
|
||||
bbox = bbox[mask == 1,:]
|
||||
|
||||
|
||||
return bbox
|
||||
|
||||
|
||||
def rotate_im(image, angle):
|
||||
"""Rotate the image.
|
||||
|
||||
Rotate the image such that the rotated image is enclosed inside the tightest
|
||||
rectangle. The area not occupied by the pixels of the original image is colored
|
||||
black.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
image : numpy.ndarray
|
||||
numpy image
|
||||
|
||||
angle : float
|
||||
angle by which the image is to be rotated
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndarray
|
||||
Rotated Image
|
||||
|
||||
"""
|
||||
# grab the dimensions of the image and then determine the
|
||||
# centre
|
||||
(h, w) = image.shape[:2]
|
||||
(cX, cY) = (w // 2, h // 2)
|
||||
|
||||
# grab the rotation matrix (applying the negative of the
|
||||
# angle to rotate clockwise), then grab the sine and cosine
|
||||
# (i.e., the rotation components of the matrix)
|
||||
M = cv2.getRotationMatrix2D((cX, cY), angle, 1.0)
|
||||
cos = np.abs(M[0, 0])
|
||||
sin = np.abs(M[0, 1])
|
||||
|
||||
# compute the new bounding dimensions of the image
|
||||
nW = int((h * sin) + (w * cos))
|
||||
nH = int((h * cos) + (w * sin))
|
||||
|
||||
# adjust the rotation matrix to take into account translation
|
||||
M[0, 2] += (nW / 2) - cX
|
||||
M[1, 2] += (nH / 2) - cY
|
||||
|
||||
# perform the actual rotation and return the image
|
||||
image = cv2.warpAffine(image, M, (nW, nH))
|
||||
|
||||
# image = cv2.resize(image, (w,h))
|
||||
return image
|
||||
|
||||
def get_corners(bboxes):
|
||||
|
||||
"""Get corners of bounding boxes
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
bboxes: numpy.ndarray
|
||||
Numpy array containing bounding boxes of shape `N X 4` where N is the
|
||||
number of bounding boxes and the bounding boxes are represented in the
|
||||
format `x1 y1 x2 y2`
|
||||
|
||||
returns
|
||||
-------
|
||||
|
||||
numpy.ndarray
|
||||
Numpy array of shape `N x 8` containing N bounding boxes each described by their
|
||||
corner co-ordinates `x1 y1 x2 y2 x3 y3 x4 y4`
|
||||
|
||||
"""
|
||||
width = (bboxes[:,2] - bboxes[:,0]).reshape(-1,1)
|
||||
height = (bboxes[:,3] - bboxes[:,1]).reshape(-1,1)
|
||||
|
||||
x1 = bboxes[:,0].reshape(-1,1)
|
||||
y1 = bboxes[:,1].reshape(-1,1)
|
||||
|
||||
x2 = x1 + width
|
||||
y2 = y1
|
||||
|
||||
x3 = x1
|
||||
y3 = y1 + height
|
||||
|
||||
x4 = bboxes[:,2].reshape(-1,1)
|
||||
y4 = bboxes[:,3].reshape(-1,1)
|
||||
|
||||
corners = np.hstack((x1,y1,x2,y2,x3,y3,x4,y4))
|
||||
|
||||
return corners
|
||||
|
||||
def rotate_box(corners,angle, cx, cy, h, w):
|
||||
|
||||
"""Rotate the bounding box.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
corners : numpy.ndarray
|
||||
Numpy array of shape `N x 8` containing N bounding boxes each described by their
|
||||
corner co-ordinates `x1 y1 x2 y2 x3 y3 x4 y4`
|
||||
|
||||
angle : float
|
||||
angle by which the image is to be rotated
|
||||
|
||||
cx : int
|
||||
x coordinate of the center of image (about which the box will be rotated)
|
||||
|
||||
cy : int
|
||||
y coordinate of the center of image (about which the box will be rotated)
|
||||
|
||||
h : int
|
||||
height of the image
|
||||
|
||||
w : int
|
||||
width of the image
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndarray
|
||||
Numpy array of shape `N x 8` containing N rotated bounding boxes each described by their
|
||||
corner co-ordinates `x1 y1 x2 y2 x3 y3 x4 y4`
|
||||
"""
|
||||
|
||||
corners = corners.reshape(-1,2)
|
||||
corners = np.hstack((corners, np.ones((corners.shape[0],1), dtype = type(corners[0][0]))))
|
||||
|
||||
M = cv2.getRotationMatrix2D((cx, cy), angle, 1.0)
|
||||
|
||||
|
||||
cos = np.abs(M[0, 0])
|
||||
sin = np.abs(M[0, 1])
|
||||
|
||||
nW = int((h * sin) + (w * cos))
|
||||
nH = int((h * cos) + (w * sin))
|
||||
# adjust the rotation matrix to take into account translation
|
||||
M[0, 2] += (nW / 2) - cx
|
||||
M[1, 2] += (nH / 2) - cy
|
||||
# Prepare the vector to be transformed
|
||||
calculated = np.dot(M,corners.T).T
|
||||
|
||||
calculated = calculated.reshape(-1,8)
|
||||
|
||||
return calculated
|
||||
|
||||
|
||||
def get_enclosing_box(corners):
|
||||
"""Get an enclosing box for ratated corners of a bounding box
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
corners : numpy.ndarray
|
||||
Numpy array of shape `N x 8` containing N bounding boxes each described by their
|
||||
corner co-ordinates `x1 y1 x2 y2 x3 y3 x4 y4`
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndarray
|
||||
Numpy array containing enclosing bounding boxes of shape `N X 4` where N is the
|
||||
number of bounding boxes and the bounding boxes are represented in the
|
||||
format `x1 y1 x2 y2`
|
||||
|
||||
"""
|
||||
x_ = corners[:,[0,2,4,6]]
|
||||
y_ = corners[:,[1,3,5,7]]
|
||||
|
||||
xmin = np.min(x_,1).reshape(-1,1)
|
||||
ymin = np.min(y_,1).reshape(-1,1)
|
||||
xmax = np.max(x_,1).reshape(-1,1)
|
||||
ymax = np.max(y_,1).reshape(-1,1)
|
||||
|
||||
final = np.hstack((xmin, ymin, xmax, ymax,corners[:,8:]))
|
||||
|
||||
return final
|
||||
|
||||
|
||||
def letterbox_image(img, inp_dim):
|
||||
'''resize image with unchanged aspect ratio using padding
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
img : numpy.ndarray
|
||||
Image
|
||||
|
||||
inp_dim: tuple(int)
|
||||
shape of the reszied image
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndarray:
|
||||
Resized image
|
||||
|
||||
'''
|
||||
|
||||
inp_dim = (inp_dim, inp_dim)
|
||||
img_w, img_h = img.shape[1], img.shape[0]
|
||||
w, h = inp_dim
|
||||
new_w = int(img_w * min(w/img_w, h/img_h))
|
||||
new_h = int(img_h * min(w/img_w, h/img_h))
|
||||
resized_image = cv2.resize(img, (new_w,new_h))
|
||||
|
||||
canvas = np.full((inp_dim[1], inp_dim[0], 3), 0)
|
||||
|
||||
canvas[(h-new_h)//2:(h-new_h)//2 + new_h,(w-new_w)//2:(w-new_w)//2 + new_w, :] = resized_image
|
||||
|
||||
return canvas
|
||||
Reference in New Issue
Block a user