Spaces:
Runtime error
Runtime error
Commit
·
f8112c8
1
Parent(s):
9e6296d
Upload postprocess.py
Browse files- postprocess.py +178 -0
postprocess.py
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from PIL import Image
|
| 3 |
+
import math
|
| 4 |
+
|
| 5 |
+
def findEuclideanDistance(source_representation, test_representation):
|
| 6 |
+
euclidean_distance = source_representation - test_representation
|
| 7 |
+
euclidean_distance = np.sum(np.multiply(euclidean_distance, euclidean_distance))
|
| 8 |
+
euclidean_distance = np.sqrt(euclidean_distance)
|
| 9 |
+
return euclidean_distance
|
| 10 |
+
|
| 11 |
+
#this function copied from the deepface repository: https://github.com/serengil/deepface/blob/master/deepface/commons/functions.py
|
| 12 |
+
def alignment_procedure(img, left_eye, right_eye, nose):
|
| 13 |
+
|
| 14 |
+
#this function aligns given face in img based on left and right eye coordinates
|
| 15 |
+
|
| 16 |
+
left_eye_x, left_eye_y = left_eye
|
| 17 |
+
right_eye_x, right_eye_y = right_eye
|
| 18 |
+
|
| 19 |
+
#-----------------------
|
| 20 |
+
upside_down = False
|
| 21 |
+
if nose[1] < left_eye[1] or nose[1] < right_eye[1]:
|
| 22 |
+
upside_down = True
|
| 23 |
+
|
| 24 |
+
#-----------------------
|
| 25 |
+
#find rotation direction
|
| 26 |
+
|
| 27 |
+
if left_eye_y > right_eye_y:
|
| 28 |
+
point_3rd = (right_eye_x, left_eye_y)
|
| 29 |
+
direction = -1 #rotate same direction to clock
|
| 30 |
+
else:
|
| 31 |
+
point_3rd = (left_eye_x, right_eye_y)
|
| 32 |
+
direction = 1 #rotate inverse direction of clock
|
| 33 |
+
|
| 34 |
+
#-----------------------
|
| 35 |
+
#find length of triangle edges
|
| 36 |
+
|
| 37 |
+
a = findEuclideanDistance(np.array(left_eye), np.array(point_3rd))
|
| 38 |
+
b = findEuclideanDistance(np.array(right_eye), np.array(point_3rd))
|
| 39 |
+
c = findEuclideanDistance(np.array(right_eye), np.array(left_eye))
|
| 40 |
+
|
| 41 |
+
#-----------------------
|
| 42 |
+
|
| 43 |
+
#apply cosine rule
|
| 44 |
+
|
| 45 |
+
if b != 0 and c != 0: #this multiplication causes division by zero in cos_a calculation
|
| 46 |
+
|
| 47 |
+
cos_a = (b*b + c*c - a*a)/(2*b*c)
|
| 48 |
+
|
| 49 |
+
#PR15: While mathematically cos_a must be within the closed range [-1.0, 1.0], floating point errors would produce cases violating this
|
| 50 |
+
#In fact, we did come across a case where cos_a took the value 1.0000000169176173, which lead to a NaN from the following np.arccos step
|
| 51 |
+
cos_a = min(1.0, max(-1.0, cos_a))
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
angle = np.arccos(cos_a) #angle in radian
|
| 55 |
+
angle = (angle * 180) / math.pi #radian to degree
|
| 56 |
+
|
| 57 |
+
#-----------------------
|
| 58 |
+
#rotate base image
|
| 59 |
+
|
| 60 |
+
if direction == -1:
|
| 61 |
+
angle = 90 - angle
|
| 62 |
+
|
| 63 |
+
if upside_down == True:
|
| 64 |
+
angle = angle + 90
|
| 65 |
+
|
| 66 |
+
img = Image.fromarray(img)
|
| 67 |
+
img = np.array(img.rotate(direction * angle))
|
| 68 |
+
|
| 69 |
+
#-----------------------
|
| 70 |
+
|
| 71 |
+
return img #return img anyway
|
| 72 |
+
|
| 73 |
+
#this function is copied from the following code snippet: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/retinaface.py
|
| 74 |
+
def bbox_pred(boxes, box_deltas):
|
| 75 |
+
if boxes.shape[0] == 0:
|
| 76 |
+
return np.zeros((0, box_deltas.shape[1]))
|
| 77 |
+
|
| 78 |
+
boxes = boxes.astype(np.float, copy=False)
|
| 79 |
+
widths = boxes[:, 2] - boxes[:, 0] + 1.0
|
| 80 |
+
heights = boxes[:, 3] - boxes[:, 1] + 1.0
|
| 81 |
+
ctr_x = boxes[:, 0] + 0.5 * (widths - 1.0)
|
| 82 |
+
ctr_y = boxes[:, 1] + 0.5 * (heights - 1.0)
|
| 83 |
+
|
| 84 |
+
dx = box_deltas[:, 0:1]
|
| 85 |
+
dy = box_deltas[:, 1:2]
|
| 86 |
+
dw = box_deltas[:, 2:3]
|
| 87 |
+
dh = box_deltas[:, 3:4]
|
| 88 |
+
|
| 89 |
+
pred_ctr_x = dx * widths[:, np.newaxis] + ctr_x[:, np.newaxis]
|
| 90 |
+
pred_ctr_y = dy * heights[:, np.newaxis] + ctr_y[:, np.newaxis]
|
| 91 |
+
pred_w = np.exp(dw) * widths[:, np.newaxis]
|
| 92 |
+
pred_h = np.exp(dh) * heights[:, np.newaxis]
|
| 93 |
+
|
| 94 |
+
pred_boxes = np.zeros(box_deltas.shape)
|
| 95 |
+
# x1
|
| 96 |
+
pred_boxes[:, 0:1] = pred_ctr_x - 0.5 * (pred_w - 1.0)
|
| 97 |
+
# y1
|
| 98 |
+
pred_boxes[:, 1:2] = pred_ctr_y - 0.5 * (pred_h - 1.0)
|
| 99 |
+
# x2
|
| 100 |
+
pred_boxes[:, 2:3] = pred_ctr_x + 0.5 * (pred_w - 1.0)
|
| 101 |
+
# y2
|
| 102 |
+
pred_boxes[:, 3:4] = pred_ctr_y + 0.5 * (pred_h - 1.0)
|
| 103 |
+
|
| 104 |
+
if box_deltas.shape[1]>4:
|
| 105 |
+
pred_boxes[:,4:] = box_deltas[:,4:]
|
| 106 |
+
|
| 107 |
+
return pred_boxes
|
| 108 |
+
|
| 109 |
+
# This function copied from the following code snippet: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/retinaface.py
|
| 110 |
+
def landmark_pred(boxes, landmark_deltas):
|
| 111 |
+
if boxes.shape[0] == 0:
|
| 112 |
+
return np.zeros((0, landmark_deltas.shape[1]))
|
| 113 |
+
boxes = boxes.astype(np.float, copy=False)
|
| 114 |
+
widths = boxes[:, 2] - boxes[:, 0] + 1.0
|
| 115 |
+
heights = boxes[:, 3] - boxes[:, 1] + 1.0
|
| 116 |
+
ctr_x = boxes[:, 0] + 0.5 * (widths - 1.0)
|
| 117 |
+
ctr_y = boxes[:, 1] + 0.5 * (heights - 1.0)
|
| 118 |
+
pred = landmark_deltas.copy()
|
| 119 |
+
for i in range(5):
|
| 120 |
+
pred[:,i,0] = landmark_deltas[:,i,0]*widths + ctr_x
|
| 121 |
+
pred[:,i,1] = landmark_deltas[:,i,1]*heights + ctr_y
|
| 122 |
+
return pred
|
| 123 |
+
|
| 124 |
+
# This function copied from rcnn module of retinaface-tf2 project: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/rcnn/processing/bbox_transform.py
|
| 125 |
+
def clip_boxes(boxes, im_shape):
|
| 126 |
+
# x1 >= 0
|
| 127 |
+
boxes[:, 0::4] = np.maximum(np.minimum(boxes[:, 0::4], im_shape[1] - 1), 0)
|
| 128 |
+
# y1 >= 0
|
| 129 |
+
boxes[:, 1::4] = np.maximum(np.minimum(boxes[:, 1::4], im_shape[0] - 1), 0)
|
| 130 |
+
# x2 < im_shape[1]
|
| 131 |
+
boxes[:, 2::4] = np.maximum(np.minimum(boxes[:, 2::4], im_shape[1] - 1), 0)
|
| 132 |
+
# y2 < im_shape[0]
|
| 133 |
+
boxes[:, 3::4] = np.maximum(np.minimum(boxes[:, 3::4], im_shape[0] - 1), 0)
|
| 134 |
+
return boxes
|
| 135 |
+
|
| 136 |
+
#this function is mainly based on the following code snippet: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/rcnn/cython/anchors.pyx
|
| 137 |
+
def anchors_plane(height, width, stride, base_anchors):
|
| 138 |
+
A = base_anchors.shape[0]
|
| 139 |
+
c_0_2 = np.tile(np.arange(0, width)[np.newaxis, :, np.newaxis, np.newaxis], (height, 1, A, 1))
|
| 140 |
+
c_1_3 = np.tile(np.arange(0, height)[:, np.newaxis, np.newaxis, np.newaxis], (1, width, A, 1))
|
| 141 |
+
all_anchors = np.concatenate([c_0_2, c_1_3, c_0_2, c_1_3], axis=-1) * stride + np.tile(base_anchors[np.newaxis, np.newaxis, :, :], (height, width, 1, 1))
|
| 142 |
+
return all_anchors
|
| 143 |
+
|
| 144 |
+
#this function is mainly based on the following code snippet: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/rcnn/cython/cpu_nms.pyx
|
| 145 |
+
#Fast R-CNN by Ross Girshick
|
| 146 |
+
def cpu_nms(dets, threshold):
|
| 147 |
+
x1 = dets[:, 0]
|
| 148 |
+
y1 = dets[:, 1]
|
| 149 |
+
x2 = dets[:, 2]
|
| 150 |
+
y2 = dets[:, 3]
|
| 151 |
+
scores = dets[:, 4]
|
| 152 |
+
|
| 153 |
+
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
|
| 154 |
+
order = scores.argsort()[::-1]
|
| 155 |
+
|
| 156 |
+
ndets = dets.shape[0]
|
| 157 |
+
suppressed = np.zeros((ndets), dtype=np.int)
|
| 158 |
+
|
| 159 |
+
keep = []
|
| 160 |
+
for _i in range(ndets):
|
| 161 |
+
i = order[_i]
|
| 162 |
+
if suppressed[i] == 1:
|
| 163 |
+
continue
|
| 164 |
+
keep.append(i)
|
| 165 |
+
ix1 = x1[i]; iy1 = y1[i]; ix2 = x2[i]; iy2 = y2[i]
|
| 166 |
+
iarea = areas[i]
|
| 167 |
+
for _j in range(_i + 1, ndets):
|
| 168 |
+
j = order[_j]
|
| 169 |
+
if suppressed[j] == 1:
|
| 170 |
+
continue
|
| 171 |
+
xx1 = max(ix1, x1[j]); yy1 = max(iy1, y1[j]); xx2 = min(ix2, x2[j]); yy2 = min(iy2, y2[j])
|
| 172 |
+
w = max(0.0, xx2 - xx1 + 1); h = max(0.0, yy2 - yy1 + 1)
|
| 173 |
+
inter = w * h
|
| 174 |
+
ovr = inter / (iarea + areas[j] - inter)
|
| 175 |
+
if ovr >= threshold:
|
| 176 |
+
suppressed[j] = 1
|
| 177 |
+
|
| 178 |
+
return keep
|