Spaces:
Runtime error
Runtime error
""" | |
Align face and image sizes | |
""" | |
import cv2 | |
import numpy as np | |
def positive_cap(num): | |
""" Cap a number to ensure positivity | |
:param num: positive or negative number | |
:returns: (overflow, capped_number) | |
""" | |
if num < 0: | |
return 0, abs(num) | |
else: | |
return num, 0 | |
def roi_coordinates(rect, size, scale): | |
""" Align the rectangle into the center and return the top-left coordinates | |
within the new size. If rect is smaller, we add borders. | |
:param rect: (x, y, w, h) bounding rectangle of the face | |
:param size: (width, height) are the desired dimensions | |
:param scale: scaling factor of the rectangle to be resized | |
:returns: 4 numbers. Top-left coordinates of the aligned ROI. | |
(x, y, border_x, border_y). All values are > 0. | |
""" | |
rectx, recty, rectw, recth = rect | |
new_height, new_width = size | |
mid_x = int((rectx + rectw/2) * scale) | |
mid_y = int((recty + recth/2) * scale) | |
roi_x = mid_x - int(new_width/2) | |
roi_y = mid_y - int(new_height/2) | |
roi_x, border_x = positive_cap(roi_x) | |
roi_y, border_y = positive_cap(roi_y) | |
return roi_x, roi_y, border_x, border_y | |
def scaling_factor(rect, size): | |
""" Calculate the scaling factor for the current image to be | |
resized to the new dimensions | |
:param rect: (x, y, w, h) bounding rectangle of the face | |
:param size: (width, height) are the desired dimensions | |
:returns: floating point scaling factor | |
""" | |
new_height, new_width = size | |
rect_h, rect_w = rect[2:] | |
height_ratio = rect_h / new_height | |
width_ratio = rect_w / new_width | |
scale = 1 | |
if height_ratio > width_ratio: | |
new_recth = 0.8 * new_height | |
scale = new_recth / rect_h | |
else: | |
new_rectw = 0.8 * new_width | |
scale = new_rectw / rect_w | |
return scale | |
def resize_image(img, scale): | |
""" Resize image with the provided scaling factor | |
:param img: image to be resized | |
:param scale: scaling factor for resizing the image | |
""" | |
cur_height, cur_width = img.shape[:2] | |
new_scaled_height = int(scale * cur_height) | |
new_scaled_width = int(scale * cur_width) | |
return cv2.resize(img, (new_scaled_width, new_scaled_height)) | |
def resize_align(img, points, size): | |
""" Resize image and associated points, align face to the center | |
and crop to the desired size | |
:param img: image to be resized | |
:param points: *m* x 2 array of points | |
:param size: (height, width) tuple of new desired size | |
""" | |
new_height, new_width = size | |
# Resize image based on bounding rectangle | |
rect = cv2.boundingRect(np.array([points], np.int32)) | |
scale = scaling_factor(rect, size) | |
img = resize_image(img, scale) | |
# Align bounding rect to center | |
cur_height, cur_width = img.shape[:2] | |
roi_x, roi_y, border_x, border_y = roi_coordinates(rect, size, scale) | |
roi_h = np.min([new_height-border_y, cur_height-roi_y]) | |
roi_w = np.min([new_width-border_x, cur_width-roi_x]) | |
# Crop to supplied size | |
crop = np.zeros((new_height, new_width, 3), img.dtype) | |
crop[border_y:border_y+roi_h, border_x:border_x+roi_w] = ( | |
img[roi_y:roi_y+roi_h, roi_x:roi_x+roi_w]) | |
# Scale and align face points to the crop | |
points[:, 0] = (points[:, 0] * scale) + (border_x - roi_x) | |
points[:, 1] = (points[:, 1] * scale) + (border_y - roi_y) | |
return (crop, points) | |