hassan526 commited on
Commit
e14c37a
1 Parent(s): 67635af

Update app.py

Browse files

add new liveness api

Files changed (1) hide show
  1. app.py +192 -191
app.py CHANGED
@@ -80,189 +80,7 @@ def convert_fun(input_str):
80
  # Remove line breaks and extra whitespaces
81
  return ' '.join(input_str.split())
82
 
83
- def get_attributes(json):
84
- liveness_thr = 0.5
85
- liveness = "GENUINE" if json.get('liveness') >= liveness_thr else "FAKE"
86
- attr = json.get('attribute')
87
- age = attr.get('age')
88
- gender = attr.get('gender')
89
- emotion = attr.get('emotion')
90
- ethnicity = attr.get('ethnicity')
91
-
92
- mask = attr.get('face_mask')
93
- glass = 'No Glasses'
94
- if attr.get('glasses') == 'USUAL':
95
- glass = 'Glasses'
96
- if attr.get('glasses') == 'DARK':
97
- glass = 'Sunglasses'
98
-
99
- open_eye_thr = 0.3
100
- left_eye = 'Close'
101
- if attr.get('eye_left') >= open_eye_thr:
102
- left_eye = 'Open'
103
-
104
- right_eye = 'Close'
105
- if attr.get('eye_right') >= open_eye_thr:
106
- right_eye = 'Open'
107
-
108
- facehair = attr.get('facial_hair')
109
- haircolor = attr.get('hair_color')
110
- hairtype = attr.get('hair_type')
111
- headwear = attr.get('headwear')
112
-
113
- eating = 'No'
114
- eat_thr = 0.5
115
- if attr.get('food_consumption') >= eat_thr:
116
- eating = 'Yes'
117
-
118
- phone_record_thr = 0.5
119
- phone_recording = 'No'
120
- if attr.get('phone_recording') >= phone_record_thr:
121
- phone_recording = 'Yes'
122
-
123
- phone_use_thr = 0.5
124
- phone_use = 'No'
125
- if attr.get('phone_use') >= phone_use_thr:
126
- phone_use = 'Yes'
127
-
128
- seatbelt = 'No'
129
- seatbelt_thr = 0.5
130
- if attr.get('seatbelt') >= seatbelt_thr:
131
- seatbelt = 'Yes'
132
-
133
- smoking = 'No'
134
- smoking_thr = 0.5
135
- if attr.get('smoking') >= smoking_thr:
136
- smoking = 'Yes'
137
-
138
- pitch = attr.get('pitch')
139
- roll = attr.get('roll')
140
- yaw = attr.get('yaw')
141
- quality = attr.get('quality')
142
-
143
- attribute = f"""
144
- <br/>
145
- <div class="markdown-attribute-container">
146
- <table>
147
- <tr>
148
- <th style="text-align: center;">Attribute</th>
149
- <th style="text-align: center;">Result</th>
150
- <th style="text-align: center;">Score</th>
151
- <th style="text-align: center;">Threshold</th>
152
- </tr>
153
- <tr>
154
- <td>Liveness</td>
155
- <td>{liveness}</td>
156
- <td>{"{:.4f}".format(json.get('liveness'))}</td>
157
- <td>{liveness_thr}</td>
158
- </tr>
159
- <tr>
160
- <td>Gender</td>
161
- <td>{gender}</td>
162
- <td></td><td></td>
163
- </tr>
164
- <tr>
165
- <td>Age</td>
166
- <td>{int(age)}</td>
167
- <td></td><td></td>
168
- </tr>
169
- <tr>
170
- <td>Pitch</td>
171
- <td>{"{:.4f}".format(pitch)}</td>
172
- <td></td><td></td>
173
- </tr>
174
- <tr>
175
- <td>Yaw</td>
176
- <td>{"{:.4f}".format(yaw)}</td>
177
- <td></td><td></td>
178
- </tr>
179
- <tr>
180
- <td>Roll</td>
181
- <td>{"{:.4f}".format(roll)}</td>
182
- <td></td><td></td>
183
- </tr>
184
- <tr>
185
- <td>Emotion</td>
186
- <td>{emotion}</td>
187
- <td></td><td></td>
188
- </tr>
189
- <tr>
190
- <td>Left Eye</td>
191
- <td>{left_eye}</td>
192
- <td>{"{:.4f}".format(attr.get('eye_left'))}</td>
193
- <td>{open_eye_thr}</td>
194
- </tr>
195
- <tr>
196
- <td>Right Eye</td>
197
- <td>{right_eye}</td>
198
- <td>{"{:.4f}".format(attr.get('eye_right'))}</td>
199
- <td>{open_eye_thr}</td>
200
- </tr>
201
- <tr>
202
- <td>Mask</td>
203
- <td>{mask}</td>
204
- <td></td><td></td>
205
- </tr>
206
- <tr>
207
- <td>Glass</td>
208
- <td>{glass}</td>
209
- <td></td><td></td>
210
- </tr>
211
- <tr>
212
- <td>FaceHair</td>
213
- <td>{facehair}</td>
214
- <td></td><td></td>
215
- </tr>
216
- <tr>
217
- <td>HairColor</td>
218
- <td>{haircolor}</td>
219
- <td></td><td></td>
220
- </tr>
221
- <tr>
222
- <td>HairType</td>
223
- <td>{hairtype}</td>
224
- <td></td><td></td>
225
- </tr>
226
- <tr>
227
- <td>HeadWear</td>
228
- <td>{headwear}</td>
229
- <td></td><td></td>
230
- </tr>
231
- <tr>
232
- <td>Eating</td>
233
- <td>{eating}</td>
234
- <td>{"{:.4f}".format(attr.get('food_consumption'))}</td>
235
- <td>{eat_thr}</td>
236
- </tr>
237
- <tr>
238
- <td>Phone Use</td>
239
- <td>{phone_use}</td>
240
- <td>{"{:.4f}".format(attr.get('phone_use'))}</td>
241
- <td>{phone_use_thr}</td>
242
- </tr>
243
- <tr>
244
- <td>Smoking</td>
245
- <td>{smoking}</td>
246
- <td>{"{:.4f}".format(attr.get('smoking'))}</td>
247
- <td>{smoking_thr}</td>
248
- </tr>
249
- <tr>
250
- <td>Image Quality</td>
251
- <td>{"{:.4f}".format(quality)}</td>
252
- <td></td><td></td>
253
- </tr>
254
- </table>
255
- </div>
256
- """
257
- one_line_attribute = convert_fun(attribute)
258
- if liveness == 'GENUINE':
259
- liveness_result = f"""<br/><div class="markdown-success-container"><p style="text-align: center; font-size: 20px; color: green;">Liveness Check: GENUINE</p></div>"""
260
- else:
261
- liveness_result = f"""<br/><div class="markdown-fail-container"><p style="text-align: center; font-size: 20px; color: red;">Liveness Check: FAKE</p></div>"""
262
-
263
- return liveness_result, one_line_attribute
264
-
265
- def analyze_face(frame):
266
  url = "https://recognito.p.rapidapi.com/api/analyze_face"
267
  try:
268
  files = {'image': open(frame, 'rb')}
@@ -270,16 +88,14 @@ def analyze_face(frame):
270
 
271
  r = requests.post(url=url, files=files, headers=headers)
272
  except:
273
- raise gr.Error("Please select images files!")
274
 
275
  faces = None
276
-
277
  try:
278
  image = Image.open(frame)
279
 
280
  face = Image.new('RGBA',(150, 150), (80,80,80,0))
281
-
282
- liveness, age, gender, emotion, ethnicity, mask, eye, facehair, haircolor, hairtype, headwear, activity, pitch, roll, yaw, quality = [None] * 16
283
 
284
  res = r.json().get('image')
285
  if res is not None and res:
@@ -304,11 +120,196 @@ def analyze_face(frame):
304
  resized_h = 150
305
 
306
  face_crop = face_crop.resize((int(resized_w), int(resized_h)))
307
- liveness, attribute = get_attributes(res)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  except:
309
  pass
310
 
311
- return [face_crop, liveness, attribute]
 
 
 
 
 
 
 
312
 
313
 
314
  def compare_face(frame1, frame2):
@@ -470,5 +471,5 @@ with gr.Blocks(css=css) as demo:
470
  analyze_face_button.click(analyze_face, inputs=face_input, outputs=[face_output, liveness_result, attribute_result])
471
 
472
  gr.HTML('<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FRecognito%2FFaceRecognition-LivenessDetection-FaceAnalysis"><img src="https://api.visitorbadge.io/api/combined?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FRecognito%2FFaceRecognition-LivenessDetection-FaceAnalysis&countColor=%2337d67a&style=flat&labelStyle=upper" /></a>')
473
-
474
- demo.launch(server_name="0.0.0.0", server_port=7860, show_api=False)
 
80
  # Remove line breaks and extra whitespaces
81
  return ' '.join(input_str.split())
82
 
83
+ def get_attributes(frame):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  url = "https://recognito.p.rapidapi.com/api/analyze_face"
85
  try:
86
  files = {'image': open(frame, 'rb')}
 
88
 
89
  r = requests.post(url=url, files=files, headers=headers)
90
  except:
91
+ raise gr.Error("Please select images file!")
92
 
93
  faces = None
94
+ face_crop, one_line_attribute = None, ""
95
  try:
96
  image = Image.open(frame)
97
 
98
  face = Image.new('RGBA',(150, 150), (80,80,80,0))
 
 
99
 
100
  res = r.json().get('image')
101
  if res is not None and res:
 
120
  resized_h = 150
121
 
122
  face_crop = face_crop.resize((int(resized_w), int(resized_h)))
123
+
124
+ attr = res.get('attribute')
125
+
126
+ age = attr.get('age')
127
+ gender = attr.get('gender')
128
+ emotion = attr.get('emotion')
129
+ ethnicity = attr.get('ethnicity')
130
+
131
+ mask = attr.get('face_mask')
132
+ glass = 'No Glasses'
133
+ if attr.get('glasses') == 'USUAL':
134
+ glass = 'Glasses'
135
+ if attr.get('glasses') == 'DARK':
136
+ glass = 'Sunglasses'
137
+
138
+ open_eye_thr = 0.3
139
+ left_eye = 'Close'
140
+ if attr.get('eye_left') >= open_eye_thr:
141
+ left_eye = 'Open'
142
+
143
+ right_eye = 'Close'
144
+ if attr.get('eye_right') >= open_eye_thr:
145
+ right_eye = 'Open'
146
+
147
+ facehair = attr.get('facial_hair')
148
+ haircolor = attr.get('hair_color')
149
+ hairtype = attr.get('hair_type')
150
+ headwear = attr.get('headwear')
151
+
152
+ pitch = attr.get('pitch')
153
+ roll = attr.get('roll')
154
+ yaw = attr.get('yaw')
155
+ quality = attr.get('quality')
156
+
157
+ attribute = f"""
158
+ <br/>
159
+ <div class="markdown-attribute-container">
160
+ <table>
161
+ <tr>
162
+ <th style="text-align: center;">Attribute</th>
163
+ <th style="text-align: center;">Result</th>
164
+ <th style="text-align: center;">Score</th>
165
+ <th style="text-align: center;">Threshold</th>
166
+ </tr>
167
+ <tr>
168
+ <td>Gender</td>
169
+ <td>{gender}</td>
170
+ <td></td><td></td>
171
+ </tr>
172
+ <tr>
173
+ <td>Age</td>
174
+ <td>{int(age)}</td>
175
+ <td></td><td></td>
176
+ </tr>
177
+ <tr>
178
+ <td>Pitch</td>
179
+ <td>{"{:.4f}".format(pitch)}</td>
180
+ <td></td><td></td>
181
+ </tr>
182
+ <tr>
183
+ <td>Yaw</td>
184
+ <td>{"{:.4f}".format(yaw)}</td>
185
+ <td></td><td></td>
186
+ </tr>
187
+ <tr>
188
+ <td>Roll</td>
189
+ <td>{"{:.4f}".format(roll)}</td>
190
+ <td></td><td></td>
191
+ </tr>
192
+ <tr>
193
+ <td>Emotion</td>
194
+ <td>{emotion}</td>
195
+ <td></td><td></td>
196
+ </tr>
197
+ <tr>
198
+ <td>Left Eye</td>
199
+ <td>{left_eye}</td>
200
+ <td>{"{:.4f}".format(attr.get('eye_left'))}</td>
201
+ <td>{open_eye_thr}</td>
202
+ </tr>
203
+ <tr>
204
+ <td>Right Eye</td>
205
+ <td>{right_eye}</td>
206
+ <td>{"{:.4f}".format(attr.get('eye_right'))}</td>
207
+ <td>{open_eye_thr}</td>
208
+ </tr>
209
+ <tr>
210
+ <td>Mask</td>
211
+ <td>{mask}</td>
212
+ <td></td><td></td>
213
+ </tr>
214
+ <tr>
215
+ <td>Glass</td>
216
+ <td>{glass}</td>
217
+ <td></td><td></td>
218
+ </tr>
219
+ <tr>
220
+ <td>FaceHair</td>
221
+ <td>{facehair}</td>
222
+ <td></td><td></td>
223
+ </tr>
224
+ <tr>
225
+ <td>HairColor</td>
226
+ <td>{haircolor}</td>
227
+ <td></td><td></td>
228
+ </tr>
229
+ <tr>
230
+ <td>HairType</td>
231
+ <td>{hairtype}</td>
232
+ <td></td><td></td>
233
+ </tr>
234
+ <tr>
235
+ <td>HeadWear</td>
236
+ <td>{headwear}</td>
237
+ <td></td><td></td>
238
+ </tr>
239
+ <tr>
240
+ <td>Image Quality</td>
241
+ <td>{"{:.4f}".format(quality)}</td>
242
+ <td></td><td></td>
243
+ </tr>
244
+ </table>
245
+ </div>
246
+ """
247
+ one_line_attribute = convert_fun(attribute)
248
+ except:
249
+ pass
250
+
251
+ return face_crop, one_line_attribute
252
+
253
+ def check_liveness(frame):
254
+
255
+ url = "https://recognito-faceliveness.p.rapidapi.com/api/check_liveness"
256
+ try:
257
+ files = {'image': open(frame, 'rb')}
258
+ headers = {"X-RapidAPI-Key": os.environ.get("API_KEY")}
259
+
260
+ r = requests.post(url=url, files=files, headers=headers)
261
+ except:
262
+ raise gr.Error("Please select images file!")
263
+
264
+ faces = None
265
+
266
+ face_crop, liveness_result, liveness_score = None, "", -200
267
+ try:
268
+ image = Image.open(frame)
269
+
270
+ face = Image.new('RGBA',(150, 150), (80,80,80,0))
271
+ res = r.json().get('data')
272
+ if res is not None and res:
273
+ face = res.get('face_rect')
274
+ x1 = face.get('x')
275
+ y1 = face.get('y')
276
+ x2 = x1 + face.get('w')
277
+ y2 = y1 + face.get('h')
278
+
279
+ if x1 < 0:
280
+ x1 = 0
281
+ if y1 < 0:
282
+ y1 = 0
283
+ if x2 >= image.width:
284
+ x2 = image.width - 1
285
+ if y2 >= image.height:
286
+ y2 = image.height - 1
287
+
288
+ face_crop = image.crop((x1, y1, x2, y2))
289
+ face_image_ratio = face_crop.width / float(face_crop.height)
290
+ resized_w = int(face_image_ratio * 150)
291
+ resized_h = 150
292
+
293
+ face_crop = face_crop.resize((int(resized_w), int(resized_h)))
294
+ liveness_score = res.get('liveness_score')
295
+ liveness = res.get('result')
296
+
297
+ if liveness == 'REAL':
298
+ liveness_result = f"""<br/><div class="markdown-success-container"><p style="text-align: center; font-size: 20px; color: green;">Liveness Check: REAL<br/>Score: {liveness_score}</p></div>"""
299
+ else:
300
+ liveness_result = f"""<br/><div class="markdown-fail-container"><p style="text-align: center; font-size: 20px; color: red;">Liveness Check: {liveness}<br/>Score: {liveness_score}</p></div>"""
301
+
302
  except:
303
  pass
304
 
305
+ return face_crop, liveness_result, liveness_score
306
+
307
+ def analyze_face(frame):
308
+ face_crop_1, liveness_result, liveness_score = check_liveness(frame)
309
+ face_crop_2, attribute = get_attributes(frame)
310
+
311
+ face_crop = face_crop_1 if (face_crop_1 is not None) else face_crop_2
312
+ return face_crop, liveness_result, attribute
313
 
314
 
315
  def compare_face(frame1, frame2):
 
471
  analyze_face_button.click(analyze_face, inputs=face_input, outputs=[face_output, liveness_result, attribute_result])
472
 
473
  gr.HTML('<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FRecognito%2FFaceRecognition-LivenessDetection-FaceAnalysis"><img src="https://api.visitorbadge.io/api/combined?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FRecognito%2FFaceRecognition-LivenessDetection-FaceAnalysis&countColor=%2337d67a&style=flat&labelStyle=upper" /></a>')
474
+
475
+ demo.launch(server_name="0.0.0.0", server_port=7880, show_api=False)