1
+ import sys
2
+ sys .path .append ('.' )
3
+
4
+ import os
5
+ import numpy as np
6
+ import base64
7
+ import io
8
+
9
+ from PIL import Image
10
+ from flask import Flask , request , jsonify
11
+ from facesdk import getMachineCode
12
+ from facesdk import setActivation
13
+ from facesdk import faceDetection
14
+ from facesdk import initSDK
15
+ from facebox import FaceBox
16
+
17
+ livenessThreshold = 0.7
18
+ yawThreshold = 10
19
+ pitchThreshold = 10
20
+ rollThreshold = 10
21
+ occlusionThreshold = 0.9
22
+ eyeClosureThreshold = 0.7
23
+ mouthOpeningThreshold = 0.5
24
+ borderRate = 0.05
25
+ smallFaceThreshold = 100
26
+ lowQualityThreshold = 0.3
27
+ hightQualityThreshold = 0.7
28
+ luminanceDarkThreshold = 50
29
+ luminanceLightThreshold = 200
30
+
31
+ maxFaceCount = 10
32
+
33
+ licensePath = "license.txt"
34
+ license = ""
35
+
36
+ machineCode = getMachineCode ()
37
+ print ("machineCode: " , machineCode .decode ('utf-8' ))
38
+
39
+ try :
40
+ with open (licensePath , 'r' ) as file :
41
+ license = file .read ()
42
+ except IOError as exc :
43
+ print ("failed to open license.txt: " , exc .errno )
44
+ print ("license: " , license )
45
+
46
+ ret = setActivation (license .encode ('utf-8' ))
47
+ print ("activation: " , ret )
48
+
49
+ ret = initSDK ("data" .encode ('utf-8' ))
50
+ print ("init: " , ret )
51
+
52
+ app = Flask (__name__ )
53
+
54
+ @app .route ('/check_liveness' , methods = ['POST' ])
55
+ def check_liveness ():
56
+ file = request .files ['file' ]
57
+ image = Image .open (file )
58
+ image_np = np .asarray (image )
59
+
60
+ faceBoxes = (FaceBox * maxFaceCount )()
61
+ faceCount = faceDetection (image_np , image_np .shape [1 ], image_np .shape [0 ], faceBoxes , maxFaceCount )
62
+
63
+ i = 0
64
+ faces = []
65
+ while (i < faceCount ):
66
+ j = 0
67
+ landmark_68 = []
68
+ while (j < 68 ):
69
+ landmark_68 .append ({"x" : faceBoxes [i ].landmark_68 [j * 2 ], "y" : faceBoxes [i ].landmark_68 [j * 2 + 1 ]})
70
+ j = j + 1
71
+ faces .append ({"x1" : faceBoxes [i ].x1 , "y1" : faceBoxes [i ].y1 , "x2" : faceBoxes [i ].x2 , "y2" : faceBoxes [i ].y2 ,
72
+ "liveness" : faceBoxes [i ].liveness ,
73
+ "yaw" : faceBoxes [i ].yaw , "roll" : faceBoxes [i ].roll , "pitch" : faceBoxes [i ].pitch ,
74
+ "face_quality" : faceBoxes [i ].face_quality , "face_luminance" : faceBoxes [i ].face_luminance , "eye_dist" : faceBoxes [i ].eye_dist ,
75
+ "left_eye_closed" : faceBoxes [i ].left_eye_closed , "right_eye_closed" : faceBoxes [i ].right_eye_closed ,
76
+ "face_occlusion" : faceBoxes [i ].face_occlusion , "mouth_opened" : faceBoxes [i ].mouth_opened ,
77
+ "landmark_68" : landmark_68 })
78
+ i = i + 1
79
+
80
+ result = ""
81
+ if faceCount == 0 :
82
+ result = "No face"
83
+ elif faceCount > 1 :
84
+ result = "Multiple face"
85
+ else :
86
+ if faceBoxes [0 ].liveness > livenessThreshold :
87
+ result = "Real"
88
+ else :
89
+ result = "Spoof"
90
+
91
+ isNotFront = True
92
+ isOcclusion = False
93
+ isEyeClosure = False
94
+ isMouthOpening = False
95
+ isBoundary = False
96
+ isSmall = False
97
+ quality = "Low"
98
+ luminance = "Dark"
99
+ if abs (faceBoxes [0 ].yaw ) < yawThreshold and abs (faceBoxes [0 ].roll ) < rollThreshold and abs (faceBoxes [0 ].pitch ) < pitchThreshold :
100
+ isNotFront = False
101
+
102
+ if faceBoxes [0 ].face_occlusion > occlusionThreshold :
103
+ isOcclusion = True
104
+
105
+ if faceBoxes [0 ].left_eye_closed > eyeClosureThreshold or faceBoxes [0 ].right_eye_closed > eyeClosureThreshold :
106
+ isEyeClosure = True
107
+
108
+ if faceBoxes [0 ].mouth_opened > mouthOpeningThreshold :
109
+ isMouthOpening = True
110
+
111
+ if (faceBoxes [0 ].x1 < image_np .shape [1 ] * borderRate or
112
+ faceBoxes [0 ].y1 < image_np .shape [0 ] * borderRate or
113
+ faceBoxes [0 ].x1 > image_np .shape [1 ] - image_np .shape [1 ] * borderRate or
114
+ faceBoxes [0 ].x1 > image_np .shape [0 ] - image_np .shape [0 ] * borderRate ):
115
+ isBoundary = True
116
+
117
+ if faceBoxes [0 ].eye_dist < smallFaceThreshold :
118
+ isSmall = True
119
+
120
+ if faceBoxes [0 ].face_quality < lowQualityThreshold :
121
+ quality = "Low"
122
+ elif faceBoxes [0 ].face_quality < hightQualityThreshold :
123
+ quality = "Medium"
124
+ else :
125
+ quality = "High"
126
+
127
+ if faceBoxes [0 ].face_luminance < luminanceDarkThreshold :
128
+ luminance = "Dark"
129
+ elif faceBoxes [0 ].face_luminance < luminanceLightThreshold :
130
+ luminance = "Normal"
131
+ else :
132
+ luminance = "Light"
133
+
134
+ status = "ok"
135
+ faceState = {"is_not_front" : isNotFront , "is_occluded" : isOcclusion , "eye_closed" : isEyeClosure , "mouth_opened" : isMouthOpening ,
136
+ "is_boundary_face" : isBoundary , "is_small" : isSmall , "quality" : quality , "luminance" : luminance , "result" : result }
137
+ response = jsonify ({"face_state" : faceState , "faces" : faces })
138
+
139
+ response .status_code = 200
140
+ response .headers ["Content-Type" ] = "application/json; charset=utf-8"
141
+ return response
142
+
143
+ status = "ok"
144
+ response = jsonify ({"face_state" : {"result" : result }, "faces" : faces })
145
+
146
+ response .status_code = 200
147
+ response .headers ["Content-Type" ] = "application/json; charset=utf-8"
148
+ return response
149
+
150
+ @app .route ('/check_liveness_base64' , methods = ['POST' ])
151
+ def check_liveness_base64 ():
152
+ content = request .get_json ()
153
+ imageBase64 = content ['base64' ]
154
+ image_data = base64 .b64decode (imageBase64 )
155
+
156
+ image = Image .open (io .BytesIO (image_data ))
157
+ image_np = np .asarray (image )
158
+
159
+ faceBoxes = (FaceBox * maxFaceCount )()
160
+ faceCount = faceDetection (image_np , image_np .shape [1 ], image_np .shape [0 ], faceBoxes , maxFaceCount )
161
+
162
+ i = 0
163
+ faces = []
164
+ while (i < faceCount ):
165
+ j = 0
166
+ landmark_68 = []
167
+ while (j < 68 ):
168
+ landmark_68 .append ({"x" : faceBoxes [i ].landmark_68 [j * 2 ], "y" : faceBoxes [i ].landmark_68 [j * 2 + 1 ]})
169
+ j = j + 1
170
+ faces .append ({"x1" : faceBoxes [i ].x1 , "y1" : faceBoxes [i ].y1 , "x2" : faceBoxes [i ].x2 , "y2" : faceBoxes [i ].y2 ,
171
+ "liveness" : faceBoxes [i ].liveness ,
172
+ "yaw" : faceBoxes [i ].yaw , "roll" : faceBoxes [i ].roll , "pitch" : faceBoxes [i ].pitch ,
173
+ "face_quality" : faceBoxes [i ].face_quality , "face_luminance" : faceBoxes [i ].face_luminance , "eye_dist" : faceBoxes [i ].eye_dist ,
174
+ "left_eye_closed" : faceBoxes [i ].left_eye_closed , "right_eye_closed" : faceBoxes [i ].right_eye_closed ,
175
+ "face_occlusion" : faceBoxes [i ].face_occlusion , "mouth_opened" : faceBoxes [i ].mouth_opened ,
176
+ "landmark_68" : landmark_68 })
177
+ i = i + 1
178
+
179
+ result = ""
180
+ if faceCount == 0 :
181
+ result = "No face"
182
+ elif faceCount > 1 :
183
+ result = "Multiple face"
184
+ else :
185
+ if faceBoxes [0 ].liveness > livenessThreshold :
186
+ result = "Real"
187
+ else :
188
+ result = "Spoof"
189
+
190
+ isNotFront = True
191
+ isOcclusion = False
192
+ isEyeClosure = False
193
+ isMouthOpening = False
194
+ isBoundary = False
195
+ isSmall = False
196
+ quality = "Low"
197
+ luminance = "Dark"
198
+ if abs (faceBoxes [0 ].yaw ) < yawThreshold and abs (faceBoxes [0 ].roll ) < rollThreshold and abs (faceBoxes [0 ].pitch ) < pitchThreshold :
199
+ isNotFront = False
200
+
201
+ if faceBoxes [0 ].face_occlusion > occlusionThreshold :
202
+ isOcclusion = True
203
+
204
+ if faceBoxes [0 ].left_eye_closed > eyeClosureThreshold or faceBoxes [0 ].right_eye_closed > eyeClosureThreshold :
205
+ isEyeClosure = True
206
+
207
+ if faceBoxes [0 ].mouth_opened > mouthOpeningThreshold :
208
+ isMouthOpening = True
209
+
210
+ if (faceBoxes [0 ].x1 < image_np .shape [1 ] * borderRate or
211
+ faceBoxes [0 ].y1 < image_np .shape [0 ] * borderRate or
212
+ faceBoxes [0 ].x1 > image_np .shape [1 ] - image_np .shape [1 ] * borderRate or
213
+ faceBoxes [0 ].x1 > image_np .shape [0 ] - image_np .shape [0 ] * borderRate ):
214
+ isBoundary = True
215
+
216
+ if faceBoxes [0 ].eye_dist < smallFaceThreshold :
217
+ isSmall = True
218
+
219
+ if faceBoxes [0 ].face_quality < lowQualityThreshold :
220
+ quality = "Low"
221
+ elif faceBoxes [0 ].face_quality < hightQualityThreshold :
222
+ quality = "Medium"
223
+ else :
224
+ quality = "High"
225
+
226
+ if faceBoxes [0 ].face_luminance < luminanceDarkThreshold :
227
+ luminance = "Dark"
228
+ elif faceBoxes [0 ].face_luminance < luminanceLightThreshold :
229
+ luminance = "Normal"
230
+ else :
231
+ luminance = "Light"
232
+
233
+ status = "ok"
234
+ faceState = {"is_not_front" : isNotFront , "is_occluded" : isOcclusion , "eye_closed" : isEyeClosure , "mouth_opened" : isMouthOpening ,
235
+ "is_boundary_face" : isBoundary , "is_small" : isSmall , "quality" : quality , "luminance" : luminance , "result" : result }
236
+ response = jsonify ({"face_state" : faceState , "faces" : faces })
237
+
238
+ response .status_code = 200
239
+ response .headers ["Content-Type" ] = "application/json; charset=utf-8"
240
+ return response
241
+
242
+ status = "ok"
243
+ response = jsonify ({"face_state" : {"result" : result }, "faces" : faces })
244
+
245
+ response .status_code = 200
246
+ response .headers ["Content-Type" ] = "application/json; charset=utf-8"
247
+ return response
248
+
249
+
250
+ if __name__ == '__main__' :
251
+ port = int (os .environ .get ("PORT" , 8080 ))
252
+ app .run (host = '0.0.0.0' , port = port )
0 commit comments