Path: blob/master/Face-Recognition-with-ArcFace/align/box_utils.py
3142 views
import numpy as np1from PIL import Image234def nms(boxes, overlap_threshold = 0.5, mode = 'union'):5"""Non-maximum suppression.67Arguments:8boxes: a float numpy array of shape [n, 5],9where each row is (xmin, ymin, xmax, ymax, score).10overlap_threshold: a float number.11mode: 'union' or 'min'.1213Returns:14list with indices of the selected boxes15"""1617# if there are no boxes, return the empty list18if len(boxes) == 0:19return []2021# list of picked indices22pick = []2324# grab the coordinates of the bounding boxes25x1, y1, x2, y2, score = [boxes[:, i] for i in range(5)]2627area = (x2 - x1 + 1.0)*(y2 - y1 + 1.0)28ids = np.argsort(score) # in increasing order2930while len(ids) > 0:3132# grab index of the largest value33last = len(ids) - 134i = ids[last]35pick.append(i)3637# compute intersections38# of the box with the largest score39# with the rest of boxes4041# left top corner of intersection boxes42ix1 = np.maximum(x1[i], x1[ids[:last]])43iy1 = np.maximum(y1[i], y1[ids[:last]])4445# right bottom corner of intersection boxes46ix2 = np.minimum(x2[i], x2[ids[:last]])47iy2 = np.minimum(y2[i], y2[ids[:last]])4849# width and height of intersection boxes50w = np.maximum(0.0, ix2 - ix1 + 1.0)51h = np.maximum(0.0, iy2 - iy1 + 1.0)5253# intersections' areas54inter = w * h55if mode == 'min':56overlap = inter/np.minimum(area[i], area[ids[:last]])57elif mode == 'union':58# intersection over union (IoU)59overlap = inter/(area[i] + area[ids[:last]] - inter)6061# delete all boxes where overlap is too big62ids = np.delete(63ids,64np.concatenate([[last], np.where(overlap > overlap_threshold)[0]])65)6667return pick686970def convert_to_square(bboxes):71"""Convert bounding boxes to a square form.7273Arguments:74bboxes: a float numpy array of shape [n, 5].7576Returns:77a float numpy array of shape [n, 5],78squared bounding boxes.79"""8081square_bboxes = np.zeros_like(bboxes)82x1, y1, x2, y2 = [bboxes[:, i] for i in range(4)]83h = y2 - y1 + 1.084w = x2 - x1 + 1.085max_side = np.maximum(h, w)86square_bboxes[:, 0] = x1 + w*0.5 - max_side*0.587square_bboxes[:, 1] = y1 + h*0.5 - max_side*0.588square_bboxes[:, 2] = square_bboxes[:, 0] + max_side - 1.089square_bboxes[:, 3] = square_bboxes[:, 1] + max_side - 1.090return square_bboxes919293def calibrate_box(bboxes, offsets):94"""Transform bounding boxes to be more like true bounding boxes.95'offsets' is one of the outputs of the nets.9697Arguments:98bboxes: a float numpy array of shape [n, 5].99offsets: a float numpy array of shape [n, 4].100101Returns:102a float numpy array of shape [n, 5].103"""104x1, y1, x2, y2 = [bboxes[:, i] for i in range(4)]105w = x2 - x1 + 1.0106h = y2 - y1 + 1.0107w = np.expand_dims(w, 1)108h = np.expand_dims(h, 1)109110# this is what happening here:111# tx1, ty1, tx2, ty2 = [offsets[:, i] for i in range(4)]112# x1_true = x1 + tx1*w113# y1_true = y1 + ty1*h114# x2_true = x2 + tx2*w115# y2_true = y2 + ty2*h116# below is just more compact form of this117118# are offsets always such that119# x1 < x2 and y1 < y2 ?120121translation = np.hstack([w, h, w, h])*offsets122bboxes[:, 0:4] = bboxes[:, 0:4] + translation123return bboxes124125126def get_image_boxes(bounding_boxes, img, size = 24):127"""Cut out boxes from the image.128129Arguments:130bounding_boxes: a float numpy array of shape [n, 5].131img: an instance of PIL.Image.132size: an integer, size of cutouts.133134Returns:135a float numpy array of shape [n, 3, size, size].136"""137138num_boxes = len(bounding_boxes)139width, height = img.size140141[dy, edy, dx, edx, y, ey, x, ex, w, h] = correct_bboxes(bounding_boxes, width, height)142img_boxes = np.zeros((num_boxes, 3, size, size), 'float32')143144for i in range(num_boxes):145img_box = np.zeros((h[i], w[i], 3), 'uint8')146147img_array = np.asarray(img, 'uint8')148img_box[dy[i]:(edy[i] + 1), dx[i]:(edx[i] + 1), :] =\149img_array[y[i]:(ey[i] + 1), x[i]:(ex[i] + 1), :]150151# resize152img_box = Image.fromarray(img_box)153img_box = img_box.resize((size, size), Image.BILINEAR)154img_box = np.asarray(img_box, 'float32')155156img_boxes[i, :, :, :] = _preprocess(img_box)157158return img_boxes159160161def correct_bboxes(bboxes, width, height):162"""Crop boxes that are too big and get coordinates163with respect to cutouts.164165Arguments:166bboxes: a float numpy array of shape [n, 5],167where each row is (xmin, ymin, xmax, ymax, score).168width: a float number.169height: a float number.170171Returns:172dy, dx, edy, edx: a int numpy arrays of shape [n],173coordinates of the boxes with respect to the cutouts.174y, x, ey, ex: a int numpy arrays of shape [n],175corrected ymin, xmin, ymax, xmax.176h, w: a int numpy arrays of shape [n],177just heights and widths of boxes.178179in the following order:180[dy, edy, dx, edx, y, ey, x, ex, w, h].181"""182183x1, y1, x2, y2 = [bboxes[:, i] for i in range(4)]184w, h = x2 - x1 + 1.0, y2 - y1 + 1.0185num_boxes = bboxes.shape[0]186187# 'e' stands for end188# (x, y) -> (ex, ey)189x, y, ex, ey = x1, y1, x2, y2190191# we need to cut out a box from the image.192# (x, y, ex, ey) are corrected coordinates of the box193# in the image.194# (dx, dy, edx, edy) are coordinates of the box in the cutout195# from the image.196dx, dy = np.zeros((num_boxes,)), np.zeros((num_boxes,))197edx, edy = w.copy() - 1.0, h.copy() - 1.0198199# if box's bottom right corner is too far right200ind = np.where(ex > width - 1.0)[0]201edx[ind] = w[ind] + width - 2.0 - ex[ind]202ex[ind] = width - 1.0203204# if box's bottom right corner is too low205ind = np.where(ey > height - 1.0)[0]206edy[ind] = h[ind] + height - 2.0 - ey[ind]207ey[ind] = height - 1.0208209# if box's top left corner is too far left210ind = np.where(x < 0.0)[0]211dx[ind] = 0.0 - x[ind]212x[ind] = 0.0213214# if box's top left corner is too high215ind = np.where(y < 0.0)[0]216dy[ind] = 0.0 - y[ind]217y[ind] = 0.0218219return_list = [dy, edy, dx, edx, y, ey, x, ex, w, h]220return_list = [i.astype('int32') for i in return_list]221222return return_list223224225def _preprocess(img):226"""Preprocessing step before feeding the network.227228Arguments:229img: a float numpy array of shape [h, w, c].230231Returns:232a float numpy array of shape [1, c, h, w].233"""234img = img.transpose((2, 0, 1))235img = np.expand_dims(img, 0)236img = (img - 127.5) * 0.0078125237return img238239240