conciomith commited on
Commit
66ca1ff
1 Parent(s): c303d38

Upload RetinaFace.py

Browse files
Files changed (1) hide show
  1. RetinaFace.py +216 -0
RetinaFace.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+ warnings.filterwarnings("ignore")
3
+
4
+ import os
5
+ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
6
+
7
+ #---------------------------
8
+
9
+ import numpy as np
10
+ import tensorflow as tf
11
+ import cv2
12
+
13
+ from retinaface.model import retinaface_model
14
+ from retinaface.commons import preprocess, postprocess
15
+
16
+ #---------------------------
17
+
18
+ import tensorflow as tf
19
+ tf_version = int(tf.__version__.split(".")[0])
20
+
21
+ if tf_version == 2:
22
+ import logging
23
+ tf.get_logger().setLevel(logging.ERROR)
24
+
25
+ #---------------------------
26
+
27
+ def build_model():
28
+
29
+ global model #singleton design pattern
30
+
31
+ if not "model" in globals():
32
+
33
+ model = tf.function(
34
+ retinaface_model.build_model(),
35
+ input_signature=(tf.TensorSpec(shape=[None, None, None, 3], dtype=np.float32),)
36
+ )
37
+
38
+ return model
39
+
40
+ def get_image(img_path):
41
+ if type(img_path) == str: # Load from file path
42
+ if not os.path.isfile(img_path):
43
+ raise ValueError("Input image file path (", img_path, ") does not exist.")
44
+ img = cv2.imread(img_path)
45
+
46
+ elif isinstance(img_path, np.ndarray): # Use given NumPy array
47
+ img = img_path.copy()
48
+
49
+ else:
50
+ raise ValueError("Invalid image input. Only file paths or a NumPy array accepted.")
51
+
52
+ # Validate image shape
53
+ if len(img.shape) != 3 or np.prod(img.shape) == 0:
54
+ raise ValueError("Input image needs to have 3 channels at must not be empty.")
55
+
56
+ return img
57
+
58
+ def detect_faces(img_path, threshold=0.9, model = None, allow_upscaling = True):
59
+ """
60
+ TODO: add function doc here
61
+ """
62
+
63
+ img = get_image(img_path)
64
+
65
+ #---------------------------
66
+
67
+ if model is None:
68
+ model = build_model()
69
+
70
+ #---------------------------
71
+
72
+ nms_threshold = 0.4; decay4=0.5
73
+
74
+ _feat_stride_fpn = [32, 16, 8]
75
+
76
+ _anchors_fpn = {
77
+ 'stride32': np.array([[-248., -248., 263., 263.], [-120., -120., 135., 135.]], dtype=np.float32),
78
+ 'stride16': np.array([[-56., -56., 71., 71.], [-24., -24., 39., 39.]], dtype=np.float32),
79
+ 'stride8': np.array([[-8., -8., 23., 23.], [ 0., 0., 15., 15.]], dtype=np.float32)
80
+ }
81
+
82
+ _num_anchors = {'stride32': 2, 'stride16': 2, 'stride8': 2}
83
+
84
+ #---------------------------
85
+
86
+ proposals_list = []
87
+ scores_list = []
88
+ landmarks_list = []
89
+ im_tensor, im_info, im_scale = preprocess.preprocess_image(img, allow_upscaling)
90
+ net_out = model(im_tensor)
91
+ net_out = [elt.numpy() for elt in net_out]
92
+ sym_idx = 0
93
+
94
+ for _idx, s in enumerate(_feat_stride_fpn):
95
+ _key = 'stride%s'%s
96
+ scores = net_out[sym_idx]
97
+ scores = scores[:, :, :, _num_anchors['stride%s'%s]:]
98
+
99
+ bbox_deltas = net_out[sym_idx + 1]
100
+ height, width = bbox_deltas.shape[1], bbox_deltas.shape[2]
101
+
102
+ A = _num_anchors['stride%s'%s]
103
+ K = height * width
104
+ anchors_fpn = _anchors_fpn['stride%s'%s]
105
+ anchors = postprocess.anchors_plane(height, width, s, anchors_fpn)
106
+ anchors = anchors.reshape((K * A, 4))
107
+ scores = scores.reshape((-1, 1))
108
+
109
+ bbox_stds = [1.0, 1.0, 1.0, 1.0]
110
+ bbox_deltas = bbox_deltas
111
+ bbox_pred_len = bbox_deltas.shape[3]//A
112
+ bbox_deltas = bbox_deltas.reshape((-1, bbox_pred_len))
113
+ bbox_deltas[:, 0::4] = bbox_deltas[:,0::4] * bbox_stds[0]
114
+ bbox_deltas[:, 1::4] = bbox_deltas[:,1::4] * bbox_stds[1]
115
+ bbox_deltas[:, 2::4] = bbox_deltas[:,2::4] * bbox_stds[2]
116
+ bbox_deltas[:, 3::4] = bbox_deltas[:,3::4] * bbox_stds[3]
117
+ proposals = postprocess.bbox_pred(anchors, bbox_deltas)
118
+
119
+ proposals = postprocess.clip_boxes(proposals, im_info[:2])
120
+
121
+ if s==4 and decay4<1.0:
122
+ scores *= decay4
123
+
124
+ scores_ravel = scores.ravel()
125
+ order = np.where(scores_ravel>=threshold)[0]
126
+ proposals = proposals[order, :]
127
+ scores = scores[order]
128
+
129
+ proposals[:, 0:4] /= im_scale
130
+ proposals_list.append(proposals)
131
+ scores_list.append(scores)
132
+
133
+ landmark_deltas = net_out[sym_idx + 2]
134
+ landmark_pred_len = landmark_deltas.shape[3]//A
135
+ landmark_deltas = landmark_deltas.reshape((-1, 5, landmark_pred_len//5))
136
+ landmarks = postprocess.landmark_pred(anchors, landmark_deltas)
137
+ landmarks = landmarks[order, :]
138
+
139
+ landmarks[:, :, 0:2] /= im_scale
140
+ landmarks_list.append(landmarks)
141
+ sym_idx += 3
142
+
143
+ proposals = np.vstack(proposals_list)
144
+ if proposals.shape[0]==0:
145
+ landmarks = np.zeros( (0,5,2) )
146
+ return np.zeros( (0,5) ), landmarks
147
+ scores = np.vstack(scores_list)
148
+ scores_ravel = scores.ravel()
149
+ order = scores_ravel.argsort()[::-1]
150
+
151
+ proposals = proposals[order, :]
152
+ scores = scores[order]
153
+ landmarks = np.vstack(landmarks_list)
154
+ landmarks = landmarks[order].astype(np.float32, copy=False)
155
+
156
+ pre_det = np.hstack((proposals[:,0:4], scores)).astype(np.float32, copy=False)
157
+
158
+ #nms = cpu_nms_wrapper(nms_threshold)
159
+ #keep = nms(pre_det)
160
+ keep = postprocess.cpu_nms(pre_det, nms_threshold)
161
+
162
+ det = np.hstack( (pre_det, proposals[:,4:]) )
163
+ det = det[keep, :]
164
+ landmarks = landmarks[keep]
165
+
166
+ resp = {}
167
+ for idx, face in enumerate(det):
168
+
169
+ label = 'face_'+str(idx+1)
170
+ resp[label] = {}
171
+ resp[label]["score"] = face[4]
172
+
173
+ resp[label]["facial_area"] = list(face[0:4].astype(int))
174
+
175
+ resp[label]["landmarks"] = {}
176
+ resp[label]["landmarks"]["right_eye"] = list(landmarks[idx][0])
177
+ resp[label]["landmarks"]["left_eye"] = list(landmarks[idx][1])
178
+ resp[label]["landmarks"]["nose"] = list(landmarks[idx][2])
179
+ resp[label]["landmarks"]["mouth_right"] = list(landmarks[idx][3])
180
+ resp[label]["landmarks"]["mouth_left"] = list(landmarks[idx][4])
181
+
182
+ return resp
183
+
184
+ def extract_faces(img_path, threshold=0.9, model = None, align = True, allow_upscaling = True):
185
+
186
+ resp = []
187
+
188
+ #---------------------------
189
+
190
+ img = get_image(img_path)
191
+
192
+ #---------------------------
193
+
194
+ obj = detect_faces(img_path = img, threshold = threshold, model = model, allow_upscaling = allow_upscaling)
195
+
196
+ if type(obj) == dict:
197
+ for key in obj:
198
+ identity = obj[key]
199
+
200
+ facial_area = identity["facial_area"]
201
+ facial_img = img[facial_area[1]: facial_area[3], facial_area[0]: facial_area[2]]
202
+
203
+ if align == True:
204
+ landmarks = identity["landmarks"]
205
+ left_eye = landmarks["left_eye"]
206
+ right_eye = landmarks["right_eye"]
207
+ nose = landmarks["nose"]
208
+ mouth_right = landmarks["mouth_right"]
209
+ mouth_left = landmarks["mouth_left"]
210
+
211
+ facial_img = postprocess.alignment_procedure(facial_img, right_eye, left_eye, nose)
212
+
213
+ resp.append(facial_img[:, :, ::-1])
214
+ #elif type(obj) == tuple:
215
+
216
+ return resp