-
Notifications
You must be signed in to change notification settings - Fork 0
/
facial_recog.py
149 lines (100 loc) · 4.76 KB
/
facial_recog.py
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import pickle
from keras import backend as K
K.set_image_data_format('channels_first')
from fr_utils import *
from inception_blocks_v2 import *
np.set_printoptions(threshold=np.nan)
class FaceRecognizer:
def __init__(self):
self.FRmodel = faceRecoModel(input_shape=(3, 96, 96))
self.load_weights()
# self.database = {
# "patterson": img_to_encoding("images/patterson.jpg", self.FRmodel),
# }
self.path_database = os.path.join(os.getcwd(), 'base/database.dat')
# with open(self.path_database, 'wb') as f:
# pickle.dump(self.database, f, pickle.HIGHEST_PROTOCOL)
self.database = self.load_img_data()
print(self.database)
def load_weights(self):
print('Carregando os pesos...')
self.FRmodel.compile(optimizer='adam', loss=self.triplet_loss, metrics=['accuracy'])
load_weights_from_FaceNet(self.FRmodel)
def insert_new_person(self, name, img):
# img_path = os.path.join('images', img)
self.database[name] = img_to_encoding(img, self.FRmodel)
with open(self.path_database, 'wb') as f:
pickle.dump(self.database, f, pickle.HIGHEST_PROTOCOL)
def load_img_data(self):
if os.path.exists(self.path_database):
print('>>> carregando banco')
with open(self.path_database, 'rb') as f:
return pickle.load(f)
else:
return {}
@staticmethod
def triplet_loss(y_true, y_pred, alpha=0.2):
"""
Implementação da função de erro tripla.
Argumentos:
y_true -- rótulos true (verdadeiros), necessários quando se define uma perda em Keras, não é necessário nesta função.
y_pred -- lista Python contendo três objetos:
âncora -- as codificações para uma imagem de âncora, com as dimensões (None, 128)
positiva -- as codificações para imagens positivas, com as dimensões (None, 128)
negativa -- as codificações para imagens negativas, com as dimensões (None, 128)
Returns:
loss -- número real, valor de perda (erro)
"""
anchor, positive, negative = y_pred[0], y_pred[1], y_pred[2]
# Computa a distância entre a âncora e a positiva
pos_dist = tf.reduce_sum(tf.square(anchor - positive), axis=-1)
# Computa a distância entre a âncora e a positiva
neg_dist = tf.reduce_sum(tf.square(anchor - negative), axis=-1)
# subtrai as duas distâncias anteriores e adiciona o alpha
basic_loss = pos_dist - neg_dist + alpha
# Pega o máximo entre basic_loss e 0.0
loss = tf.reduce_sum(tf.maximum(basic_loss, 0.0))
return loss
def verify(self, image_path, identity):
# Computa a codificação da imagem
encoding = img_to_encoding(image_path, self.FRmodel)
# Computa a distância entre a imagem da câmera e a imagem da base
dist = np.linalg.norm(encoding - self.database[identity])
# Libera o acesso se a distância for menor que 0.7, do contrário nega o acesso.
if dist < 0.7:
print("Olá " + str(identity) + ", bem vindo!")
door_open = True
else:
print("Você não é " + str(identity) + ", acesso negado.")
door_open = False
return dist, door_open
def who_is_it(self, image_path):
# Codifica a imagem capturada
encoding = img_to_encoding(image_path, self.FRmodel)
# Inicializa a menor distância "min_dist" com um valor muito grande, 100.
min_dist = 100
access = False
identity = ''
# Encontra a imagem com a codificação mais próxima da imagem capturada
# Itera sobre o dicionário da base de dados obtendo as chaves (names) e as codificações (db_enc).
for (name, db_enc) in self.database.items():
# Computa a distância entre a codificação da imagem capturada e a codificação acorrente da base de dados
dist = np.linalg.norm(encoding - db_enc)
# Se a distância for menor que a distância mínima, então passa a ser a nova distância mínima,
# e a identidade passa a ser o nome corrente.
if dist < min_dist:
min_dist = dist
identity = name
if min_dist > 0.7:
identity = 'Desconhecido'
min_dist = str(min_dist)
access = False
print("Não existe na base de dados.")
else:
identity = str(identity)
min_dist = str(min_dist)
access = True
print("Olá " + identity + ", a distância é " + min_dist)
identity = str(identity)
min_dist = str(min_dist)
return access, min_dist, identity