Spaces:
Running
Running
import cv2 | |
import numpy as np | |
def box_xyxy2xcycwh(bbox): | |
new_bbox = [] | |
for box in bbox: | |
x_min = min(box[0],box[2]) | |
y_min = min(box[1],box[3]) | |
x_max = max(box[0],box[2]) | |
y_max = max(box[1],box[3]) | |
new_bbox.append([(x_min+x_max)/2,(y_min+y_max)/2,x_max-x_min,y_max-y_min]) | |
return new_bbox | |
def box_xcycwh2xyxy(bbox): | |
new_bbox = [] | |
for box in bbox: | |
new_bbox.append([box[0]-box[2]/2,box[1]-box[3]/2,box[0]+box[2],box[1]+box[3]]) | |
return new_bbox | |
def box_xcycwh_rescale(image,bbox): | |
new_bbox = [] | |
try: | |
w,h= image.size | |
except: | |
h,w,c = image.shape | |
for box in bbox: | |
new_bbox.append([box[0]/w,box[1]/h,box[2]/w,box[3]/h]) | |
return new_bbox | |
def box_xcycwh_scaleBack(image,bbox): | |
new_bbox = [] | |
try: | |
w,h= image.size | |
except: | |
h,w,c = image.shape | |
for box in bbox: | |
new_bbox.append([box[0]*w,box[1]*h,box[2]*w,box[3]*h]) | |
return new_bbox | |
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 |