File size: 3,264 Bytes
ca7a857
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import os
import sys
import numpy as np
import ctypes, ctypes.util
from enum import Enum
from ctypes import *
from numpy.ctypeslib import ndpointer

def print_log(fmt): print("[LOG] \033[98m{}\033[00m" .format(fmt))
def print_info(fmt): print("[INFO] \033[92m{}\033[00m" .format(fmt))
def print_error(fmt): print("[ERR] \033[91m{}\033[00m" .format(fmt)) 
def print_warning(fmt): print("[WARNING] \033[93m{}\033[00m" .format(fmt))

class ENGINE_CODE(Enum):
    E_NO_FACE = 0
    E_ACTIVATION_ERROR = -1
    E_ENGINE_INIT_ERROR = -2
    
class LIVENESS_CODE(Enum):
    L_TOO_SMALL_FACE = -100
    L_BORDERLINE_FACE = -200
    L_TOO_TURNED_FACE = -300
    L_COVERED_FACE = -400
    L_MULTIPLE_FACE = -500
    L_DEEP_FAKE = -600

lib_path = os.path.abspath(os.path.dirname(__file__)) + '/libliveness_v7.so'
lib = cdll.LoadLibrary(lib_path)

get_version = lib.ttv_version
get_version.argtypes = []
get_version.restype = ctypes.c_char_p

get_deviceid = lib.ttv_get_hwid
get_deviceid.argtypes = []
get_deviceid.restype = ctypes.c_char_p

init_sdk = lib.ttv_init
init_sdk.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
init_sdk.restype = ctypes.c_int32

init_sdk_offline = lib.ttv_init_offline
init_sdk_offline.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
init_sdk_offline.restype = ctypes.c_int32


detect_face_rgb = lib.ttv_detect_face
detect_face_rgb.argtypes = [ndpointer(ctypes.c_ubyte, flags='C_CONTIGUOUS'), ctypes.c_int32, ctypes.c_int32, ndpointer(ctypes.c_int32, flags='C_CONTIGUOUS'), ndpointer(ctypes.c_double, flags='C_CONTIGUOUS'), ndpointer(ctypes.c_double, flags='C_CONTIGUOUS')]
detect_face_rgb.restype = ctypes.c_int32

DEFAULT_THRESHOLD = 0.5
def check_liveness(image_mat, spoof_threshold = DEFAULT_THRESHOLD):
    result = ""
    score = 0

    if image_mat is None:
        result = "Failed to open image"
        return result, None, None, None
    
    face_rect = np.zeros([4], dtype=np.int32)
    liveness_score = np.zeros([5], dtype=np.double) # [0]: liveness score [1]: Quality [2]: Blurness [3]: Occlusion [4]: Eye Distance
    angles = np.zeros([3], dtype=np.double)

    width = image_mat.shape[1]
    height = image_mat.shape[0]

    ret = detect_face_rgb(image_mat, width, height, face_rect, liveness_score, angles)
    
    if ret == ENGINE_CODE.E_ACTIVATION_ERROR.value:
        result = "ACTIVATION ERROR"
    elif ret == ENGINE_CODE.E_ENGINE_INIT_ERROR.value:
        result = "ENGINE INIT ERROR"
    elif ret == ENGINE_CODE.E_NO_FACE.value:
        result = "NO FACE"
        face_rect = None
        angles = None
        liveness_score[0] = 0
    elif ret > 1:
        result = "MULTIPLE FACES"
        face_rect = None
        angles = None
        liveness_score[0] = 0
    elif liveness_score[4] < 70:
        result = "TOO SMALL FACE"
    elif liveness_score[3] > 0.85:
        result = "COVERED FACE"
    elif face_rect[0] <= 0 or face_rect[1] <= 0 or face_rect[2] >= image_mat.shape[1] or face_rect[3] >= image_mat.shape[0]:
        result = "TOO CLOSE TO BORDERS"
    elif angles[0] > 25 or angles[1] > 25 or angles[2] > 25:
        result = "TOO TURNED FACE"
    elif liveness_score[0] > spoof_threshold:
        result = "REAL"
    else:
        result = "SPOOF"
    
    return result, face_rect, liveness_score[0], angles