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