-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFacerecognition.py
205 lines (171 loc) · 8.27 KB
/
Facerecognition.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, ZeroPadding2D, Activation, Input, concatenate
from tensorflow.keras.models import Model
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import MaxPooling2D, AveragePooling2D
from tensorflow.keras.layers import Concatenate
from tensorflow.keras.layers import Lambda, Flatten, Dense
from tensorflow.keras.initializers import glorot_uniform
from tensorflow.keras.layers import Layer
from tensorflow.keras import backend as K
from tensorflow.keras.models import load_model
K.set_image_data_format('channels_first')
import pickle
import cv2
import os.path
import os
import numpy as np
from numpy import genfromtxt
import pandas as pd
import tensorflow as tf
from utility import *
from webcam_utility import *
# ## Model
# The model makes an encoding vector consisting of 128 numbers for the input image. Two encodings are compared and if the two encodings are similar then we say that the two images are of the same person otherwise they are different.
# The model uses **Triplet loss function**. The aim is to minimize this function.
# triplet loss function
# y_pred - list containing three objects:
# anchor(None, 128) -- encodings for the anchor images
# positive(None, 128) -- encodings for the positive images
# negative(None, 128) -- encodings for the negative images
def triplet_loss(y_true, y_pred, alpha = 0.2):
anchor, positive, negative = y_pred[0], y_pred[1], y_pred[2]
# triplet formula components
pos_dist = tf.reduce_sum( tf.square(tf.subtract(anchor, positive)) )
neg_dist = tf.reduce_sum( tf.square(tf.subtract(anchor, negative)) )
basic_loss = pos_dist - neg_dist + alpha
loss = tf.maximum(basic_loss, 0.0)
return loss
# ### Loading the Model
# The model outputs a vector of 128 numbers which represent encoding for the given input image. We will be using this encoding vector for comparing two images.
# #### Input
# - This network takes as input 96x96 RGB image as its input. Specifically, inputs a tensor of shape $(m, n_C, n_H, n_W)$ , where $n_C$ = channel.
#
# #### Output
# - A matrix of shape **(m, 128)** where the 128 numbers are the encoding values for $ith$ image.
# load the model
def load_FRmodel():
FRmodel = load_model('models/model.h5', custom_objects={'triplet_loss': triplet_loss})
return FRmodel
# We will create a database of registered. For this we will use a simple dictionary and map each registered user with his/her face encoding.
# initialize the user database
# initialize the user database
def ini_user_database():
# check for existing database
if os.path.exists('database/user_dict.pickle'):
with open('database/user_dict.pickle', 'rb') as handle:
user_db = pickle.load(handle)
else:
# make a new one
# we use a dict for keeping track of mapping of each person with his/her face encoding
user_db = {}
# create the directory for saving the db pickle file
os.makedirs('database')
with open('database/user_dict.pickle', 'wb') as handle:
pickle.dump(user_db, handle, protocol=pickle.HIGHEST_PROTOCOL)
return user_db
# adds a new user face to the database using his/her image stored on disk using the image path
def add_user_img_path(user_db, FRmodel, name, img_path):
if name not in user_db:
user_db[name] = img_to_encoding(img_path, FRmodel)
# save the database
with open('database/user_dict.pickle', 'wb') as handle:
pickle.dump(user_db, handle, protocol=pickle.HIGHEST_PROTOCOL)
print('User ' + name + ' added successfully')
else:
print('The name is already registered! Try a different name.........')
# adds a new user using image taken from webcam
def add_user_webcam(user_db, FRmodel, name):
# we can use the webcam to capture the user image then get it recognized
face_found = detect_face(user_db, FRmodel)
if face_found:
#resize_img("saved_image/1.jpg","images")
if name not in user_db:
add_user_img_path(user_db, FRmodel, name, "saved_image/1.jpg")
else:
print('The name is already registered! Try a different name.........')
else:
print('There was no face found in the visible frame. Try again...........')
# deletes a registered user from database
def delete_user(user_db, name):
popped = user_db.pop(name, None)
if popped is not None:
print('User ' + name + ' deleted successfully')
# save the database
with open('database/user_dict.pickle', 'wb') as handle:
pickle.dump(user_db, handle, protocol=pickle.HIGHEST_PROTOCOL)
elif popped == None:
print('No such user !!')
# ### Putting everything together
# For making this face recognition system we are going to take the input image, find its encoding and then
# see if there is any similar encoding in the database or not. We define a threshold value to decide whether the two images are similar
# or not based on the similarity of their encodings.
def find_face(image_path, database, model, threshold=0.6):
# find the face encodings for the input image
encoding = img_to_encoding(image_path, model)
min_dist = 99999
# loop over all the recorded encodings in database
for name in database:
# find the similarity between the input encodings and claimed person's encodings using L2 norm
dist = np.linalg.norm(np.subtract(database[name], encoding))
# check if minimum distance or not
if dist < min_dist:
min_dist = dist
identity = name
if min_dist > threshold:
print("User not in the database.")
identity = 'Unknown Person'
else:
print("Hi! " + str(identity) + ", L2 distance: " + str(min_dist))
return min_dist, identity
# for doing face recognition
def do_face_recognition(user_db, FRmodel, threshold=0.7, save_loc="saved_image/1.jpg"):
# we can use the webcam to capture the user image then get it recognized
face_found = detect_face(user_db, FRmodel)
if face_found:
resize_img("saved_image/1.jpg","images")
find_face("saved_image/1.jpg", user_db, FRmodel, threshold)
else:
print('There was no face found in the visible frame. Try again...........')
def main():
FRmodel = load_FRmodel()
print('\n\nModel loaded...')
user_db = ini_user_database()
print('User database loaded')
ch = 'y'
while(ch == 'y' or ch == 'Y'):
user_input = input(
'\nEnter choice \n1. Realtime Face Recognition\n2. Recognize face\n3. Add or Delete user\n4. Quit\n')
if user_input == '1':
os.system('cls' if os.name == 'nt' else 'clear')
detect_face_realtime(user_db, FRmodel, threshold=0.6)
elif user_input == '2':
os.system('cls' if os.name == 'nt' else 'clear')
# we can use the webcam to capture the user image then get it recognized
do_face_recognition(user_db, FRmodel, threshold=0.6,
save_loc="saved_image/1.jpg")
elif user_input == '3':
os.system('cls' if os.name == 'nt' else 'clear')
print(
'1. Add user using saved image path\n2. Add user using Webcam\n3. Delete user\n')
add_ch = input()
name = input('Enter the name of the person\n')
if add_ch == '1':
img_path = input(
'Enter the image name with extension stored in images/\n')
add_user_img_path(user_db, FRmodel, name, 'images/' + img_path)
elif add_ch == '2':
add_user_webcam(user_db, FRmodel, name)
elif add_ch == '3':
delete_user(user_db, name)
else:
print('Invalid choice....\n')
elif user_input == '4':
return
else:
print('Invalid choice....\nTry again?\n')
ch = input('Continue ? y or n\n')
# clear the screen
os.system('cls' if os.name == 'nt' else 'clear')
if __name__ == main():
main()