deep_privacy2_face / dp2 /detection /box_utils_fdf.py
haakohu's picture
initial
5d756f1
raw
history blame
6.7 kB
"""
The FDF dataset expands bound boxes differently from what is used for CSE.
"""
import numpy as np
def quadratic_bounding_box(x0, y0, width, height, imshape):
# We assume that we can create a image that is quadratic without
# minimizing any of the sides
assert width <= min(imshape[:2])
assert height <= min(imshape[:2])
min_side = min(height, width)
if height != width:
side_diff = abs(height - width)
# Want to extend the shortest side
if min_side == height:
# Vertical side
height += side_diff
if height > imshape[0]:
# Take full frame, and shrink width
y0 = 0
height = imshape[0]
side_diff = abs(height - width)
width -= side_diff
x0 += side_diff // 2
else:
y0 -= side_diff // 2
y0 = max(0, y0)
else:
# Horizontal side
width += side_diff
if width > imshape[1]:
# Take full frame width, and shrink height
x0 = 0
width = imshape[1]
side_diff = abs(height - width)
height -= side_diff
y0 += side_diff // 2
else:
x0 -= side_diff // 2
x0 = max(0, x0)
# Check that bbox goes outside image
x1 = x0 + width
y1 = y0 + height
if imshape[1] < x1:
diff = x1 - imshape[1]
x0 -= diff
if imshape[0] < y1:
diff = y1 - imshape[0]
y0 -= diff
assert x0 >= 0, "Bounding box outside image."
assert y0 >= 0, "Bounding box outside image."
assert x0 + width <= imshape[1], "Bounding box outside image."
assert y0 + height <= imshape[0], "Bounding box outside image."
return x0, y0, width, height
def expand_bounding_box(bbox, percentage, imshape):
orig_bbox = bbox.copy()
x0, y0, x1, y1 = bbox
width = x1 - x0
height = y1 - y0
x0, y0, width, height = quadratic_bounding_box(
x0, y0, width, height, imshape)
expanding_factor = int(max(height, width) * percentage)
possible_max_expansion = [(imshape[0] - width) // 2,
(imshape[1] - height) // 2,
expanding_factor]
expanding_factor = min(possible_max_expansion)
# Expand height
if expanding_factor > 0:
y0 = y0 - expanding_factor
y0 = max(0, y0)
height += expanding_factor * 2
if height > imshape[0]:
y0 -= (imshape[0] - height)
height = imshape[0]
if height + y0 > imshape[0]:
y0 -= (height + y0 - imshape[0])
# Expand width
x0 = x0 - expanding_factor
x0 = max(0, x0)
width += expanding_factor * 2
if width > imshape[1]:
x0 -= (imshape[1] - width)
width = imshape[1]
if width + x0 > imshape[1]:
x0 -= (width + x0 - imshape[1])
y1 = y0 + height
x1 = x0 + width
assert y0 >= 0, "Y0 is minus"
assert height <= imshape[0], "Height is larger than image."
assert x0 + width <= imshape[1]
assert y0 + height <= imshape[0]
assert width == height, "HEIGHT IS NOT EQUAL WIDTH!!"
assert x0 >= 0, "Y0 is minus"
assert width <= imshape[1], "Height is larger than image."
# Check that original bbox is within new
x0_o, y0_o, x1_o, y1_o = orig_bbox
assert x0 <= x0_o, f"New bbox is outisde of original. O:{x0_o}, N: {x0}"
assert x1 >= x1_o, f"New bbox is outisde of original. O:{x1_o}, N: {x1}"
assert y0 <= y0_o, f"New bbox is outisde of original. O:{y0_o}, N: {y0}"
assert y1 >= y1_o, f"New bbox is outisde of original. O:{y1_o}, N: {y1}"
x0, y0, width, height = [int(_) for _ in [x0, y0, width, height]]
x1 = x0 + width
y1 = y0 + height
return np.array([x0, y0, x1, y1])
def is_keypoint_within_bbox(x0, y0, x1, y1, keypoint):
keypoint = keypoint[:, :3] # only nose + eyes are relevant
kp_X = keypoint[0, :]
kp_Y = keypoint[1, :]
within_X = np.all(kp_X >= x0) and np.all(kp_X <= x1)
within_Y = np.all(kp_Y >= y0) and np.all(kp_Y <= y1)
return within_X and within_Y
def expand_bbox_simple(bbox, percentage):
x0, y0, x1, y1 = bbox.astype(float)
width = x1 - x0
height = y1 - y0
x_c = int(x0) + width // 2
y_c = int(y0) + height // 2
avg_size = max(width, height)
new_width = avg_size * (1 + percentage)
x0 = x_c - new_width // 2
y0 = y_c - new_width // 2
x1 = x_c + new_width // 2
y1 = y_c + new_width // 2
return np.array([x0, y0, x1, y1]).astype(int)
def pad_image(im, bbox, pad_value):
x0, y0, x1, y1 = bbox
if x0 < 0:
pad_im = np.zeros((im.shape[0], abs(x0), im.shape[2]),
dtype=np.uint8) + pad_value
im = np.concatenate((pad_im, im), axis=1)
x1 += abs(x0)
x0 = 0
if y0 < 0:
pad_im = np.zeros((abs(y0), im.shape[1], im.shape[2]),
dtype=np.uint8) + pad_value
im = np.concatenate((pad_im, im), axis=0)
y1 += abs(y0)
y0 = 0
if x1 >= im.shape[1]:
pad_im = np.zeros(
(im.shape[0], x1 - im.shape[1] + 1, im.shape[2]),
dtype=np.uint8) + pad_value
im = np.concatenate((im, pad_im), axis=1)
if y1 >= im.shape[0]:
pad_im = np.zeros(
(y1 - im.shape[0] + 1, im.shape[1], im.shape[2]),
dtype=np.uint8) + pad_value
im = np.concatenate((im, pad_im), axis=0)
return im[y0:y1, x0:x1]
def clip_box(bbox, im):
bbox[0] = max(0, bbox[0])
bbox[1] = max(0, bbox[1])
bbox[2] = min(im.shape[1] - 1, bbox[2])
bbox[3] = min(im.shape[0] - 1, bbox[3])
return bbox
def cut_face(im, bbox, simple_expand=False, pad_value=0, pad_im=True):
outside_im = (bbox < 0).any() or bbox[2] > im.shape[1] or bbox[3] > im.shape[0]
if simple_expand or (outside_im and pad_im):
return pad_image(im, bbox, pad_value)
bbox = clip_box(bbox, im)
x0, y0, x1, y1 = bbox
return im[y0:y1, x0:x1]
def expand_bbox(
bbox_ltrb, imshape, simple_expand, default_to_simple=False,
expansion_factor=0.35):
assert bbox_ltrb.shape == (4,), f"BBox shape was: {bbox_ltrb.shape}"
bbox = bbox_ltrb.astype(float)
# FDF256 uses simple expand with ratio 0.4
if simple_expand:
return expand_bbox_simple(bbox, 0.4)
try:
return expand_bounding_box(bbox, expansion_factor, imshape)
except AssertionError:
return expand_bbox_simple(bbox, expansion_factor * 2)