Spaces:
Sleeping
Sleeping
Upload 2 files
Browse files- app.py +13 -0
- face_rec.py +207 -0
app.py
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
|
3 |
+
|
4 |
+
|
5 |
+
st.set_page_config(page_title='Attendance System',layout='wide')
|
6 |
+
|
7 |
+
st.header('Attendance System using Face Recognition')
|
8 |
+
|
9 |
+
with st.spinner("Loading Models and Conneting to Redis db ..."):
|
10 |
+
import face_rec
|
11 |
+
|
12 |
+
st.success('Model loaded sucesfully')
|
13 |
+
st.success('Redis db sucessfully connected')
|
face_rec.py
ADDED
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import pandas as pd
|
3 |
+
import cv2
|
4 |
+
|
5 |
+
import redis
|
6 |
+
|
7 |
+
# insight face
|
8 |
+
from insightface.app import FaceAnalysis
|
9 |
+
from sklearn.metrics import pairwise
|
10 |
+
# time
|
11 |
+
import time
|
12 |
+
from datetime import datetime
|
13 |
+
|
14 |
+
import os
|
15 |
+
|
16 |
+
|
17 |
+
|
18 |
+
|
19 |
+
# Connect to Redis Client
|
20 |
+
hostname = 'redis-11109.c321.us-east-1-2.ec2.cloud.redislabs.com'
|
21 |
+
portnumber = 11109
|
22 |
+
password = 'HI3acnzpSHJcssm7qtuuv7GmeakjIEKl'
|
23 |
+
|
24 |
+
r = redis.StrictRedis(host=hostname,
|
25 |
+
port=portnumber,
|
26 |
+
password=password)
|
27 |
+
|
28 |
+
# Retrive Data from database
|
29 |
+
def retrive_data(name):
|
30 |
+
retrive_dict= r.hgetall(name)
|
31 |
+
retrive_series = pd.Series(retrive_dict)
|
32 |
+
retrive_series = retrive_series.apply(lambda x: np.frombuffer(x,dtype=np.float32))
|
33 |
+
index = retrive_series.index
|
34 |
+
index = list(map(lambda x: x.decode(), index))
|
35 |
+
retrive_series.index = index
|
36 |
+
retrive_df = retrive_series.to_frame().reset_index()
|
37 |
+
retrive_df.columns = ['name_role','facial_features']
|
38 |
+
retrive_df[['Name','Role']] = retrive_df['name_role'].apply(lambda x: x.split('@')).apply(pd.Series)
|
39 |
+
return retrive_df[['Name','Role','facial_features']]
|
40 |
+
|
41 |
+
|
42 |
+
# configure face analysis
|
43 |
+
faceapp = FaceAnalysis(name='buffalo_sc',root='insightface_model', providers = ['CPUExecutionProvider'])
|
44 |
+
faceapp.prepare(ctx_id = 0, det_size=(640,640), det_thresh = 0.5)
|
45 |
+
|
46 |
+
# ML Search Algorithm
|
47 |
+
def ml_search_algorithm(dataframe,feature_column,test_vector,
|
48 |
+
name_role=['Name','Role'],thresh=0.5):
|
49 |
+
"""
|
50 |
+
cosine similarity base search algorithm
|
51 |
+
"""
|
52 |
+
# step-1: take the dataframe (collection of data)
|
53 |
+
dataframe = dataframe.copy()
|
54 |
+
# step-2: Index face embeding from the dataframe and convert into array
|
55 |
+
X_list = dataframe[feature_column].tolist()
|
56 |
+
x = np.asarray(X_list)
|
57 |
+
|
58 |
+
# step-3: Cal. cosine similarity
|
59 |
+
similar = pairwise.cosine_similarity(x,test_vector.reshape(1,-1))
|
60 |
+
similar_arr = np.array(similar).flatten()
|
61 |
+
dataframe['cosine'] = similar_arr
|
62 |
+
|
63 |
+
# step-4: filter the data
|
64 |
+
data_filter = dataframe.query(f'cosine >= {thresh}')
|
65 |
+
if len(data_filter) > 0:
|
66 |
+
# step-5: get the person name
|
67 |
+
data_filter.reset_index(drop=True,inplace=True)
|
68 |
+
argmax = data_filter['cosine'].argmax()
|
69 |
+
person_name, person_role = data_filter.loc[argmax][name_role]
|
70 |
+
|
71 |
+
else:
|
72 |
+
person_name = 'Unknown'
|
73 |
+
person_role = 'Unknown'
|
74 |
+
|
75 |
+
return person_name, person_role
|
76 |
+
|
77 |
+
|
78 |
+
### Real Time Prediction
|
79 |
+
# we need to save logs for every 1 mins
|
80 |
+
class RealTimePred:
|
81 |
+
def __init__(self):
|
82 |
+
self.logs = dict(name=[],role=[],current_time=[])
|
83 |
+
|
84 |
+
def reset_dict(self):
|
85 |
+
self.logs = dict(name=[],role=[],current_time=[])
|
86 |
+
|
87 |
+
def saveLogs_redis(self):
|
88 |
+
# step-1: create a logs dataframe
|
89 |
+
dataframe = pd.DataFrame(self.logs)
|
90 |
+
# step-2: drop the duplicate information (distinct name)
|
91 |
+
dataframe.drop_duplicates('name',inplace=True)
|
92 |
+
# step-3: push data to redis database (list)
|
93 |
+
# encode the data
|
94 |
+
name_list = dataframe['name'].tolist()
|
95 |
+
role_list = dataframe['role'].tolist()
|
96 |
+
ctime_list = dataframe['current_time'].tolist()
|
97 |
+
encoded_data = []
|
98 |
+
for name, role, ctime in zip(name_list, role_list, ctime_list):
|
99 |
+
if name != 'Unknown':
|
100 |
+
concat_string = f"{name}@{role}@{ctime}"
|
101 |
+
encoded_data.append(concat_string)
|
102 |
+
|
103 |
+
if len(encoded_data) >0:
|
104 |
+
r.lpush('attendance:logs',*encoded_data)
|
105 |
+
|
106 |
+
|
107 |
+
self.reset_dict()
|
108 |
+
|
109 |
+
|
110 |
+
def face_prediction(self,test_image, dataframe,feature_column,
|
111 |
+
name_role=['Name','Role'],thresh=0.5):
|
112 |
+
# step-1: find the time
|
113 |
+
current_time = str(datetime.now())
|
114 |
+
|
115 |
+
# step-1: take the test image and apply to insight face
|
116 |
+
results = faceapp.get(test_image)
|
117 |
+
test_copy = test_image.copy()
|
118 |
+
# step-2: use for loop and extract each embedding and pass to ml_search_algorithm
|
119 |
+
|
120 |
+
for res in results:
|
121 |
+
x1, y1, x2, y2 = res['bbox'].astype(int)
|
122 |
+
embeddings = res['embedding']
|
123 |
+
person_name, person_role = ml_search_algorithm(dataframe,
|
124 |
+
feature_column,
|
125 |
+
test_vector=embeddings,
|
126 |
+
name_role=name_role,
|
127 |
+
thresh=thresh)
|
128 |
+
if person_name == 'Unknown':
|
129 |
+
color =(0,0,255) # bgr
|
130 |
+
else:
|
131 |
+
color = (0,255,0)
|
132 |
+
|
133 |
+
cv2.rectangle(test_copy,(x1,y1),(x2,y2),color)
|
134 |
+
|
135 |
+
text_gen = person_name
|
136 |
+
cv2.putText(test_copy,text_gen,(x1,y1),cv2.FONT_HERSHEY_DUPLEX,0.7,color,2)
|
137 |
+
cv2.putText(test_copy,current_time,(x1,y2+10),cv2.FONT_HERSHEY_DUPLEX,0.7,color,2)
|
138 |
+
# save info in logs dict
|
139 |
+
self.logs['name'].append(person_name)
|
140 |
+
self.logs['role'].append(person_role)
|
141 |
+
self.logs['current_time'].append(current_time)
|
142 |
+
|
143 |
+
|
144 |
+
return test_copy
|
145 |
+
|
146 |
+
|
147 |
+
#### Registration Form
|
148 |
+
class RegistrationForm:
|
149 |
+
def __init__(self):
|
150 |
+
self.sample = 0
|
151 |
+
def reset(self):
|
152 |
+
self.sample = 0
|
153 |
+
|
154 |
+
def get_embedding(self,frame):
|
155 |
+
# get results from insightface model
|
156 |
+
results = faceapp.get(frame,max_num=1)
|
157 |
+
embeddings = None
|
158 |
+
for res in results:
|
159 |
+
self.sample += 1
|
160 |
+
x1, y1, x2, y2 = res['bbox'].astype(int)
|
161 |
+
cv2.rectangle(frame, (x1,y1),(x2,y2),(0,255,0),1)
|
162 |
+
# put text samples info
|
163 |
+
text = f"samples = {self.sample}"
|
164 |
+
cv2.putText(frame,text,(x1,y1),cv2.FONT_HERSHEY_DUPLEX,0.6,(255,255,0),2)
|
165 |
+
|
166 |
+
# facial features
|
167 |
+
embeddings = res['embedding']
|
168 |
+
|
169 |
+
return frame, embeddings
|
170 |
+
|
171 |
+
def save_data_in_redis_db(self,name,role):
|
172 |
+
# validation name
|
173 |
+
if name is not None:
|
174 |
+
if name.strip() != '':
|
175 |
+
key = f'{name}@{role}'
|
176 |
+
else:
|
177 |
+
return 'name_false'
|
178 |
+
else:
|
179 |
+
return 'name_false'
|
180 |
+
|
181 |
+
# if face_embedding.txt exists
|
182 |
+
if 'face_embedding.txt' not in os.listdir():
|
183 |
+
return 'file_false'
|
184 |
+
|
185 |
+
|
186 |
+
# step-1: load "face_embedding.txt"
|
187 |
+
x_array = np.loadtxt('face_embedding.txt',dtype=np.float32) # flatten array
|
188 |
+
|
189 |
+
# step-2: convert into array (proper shape)
|
190 |
+
received_samples = int(x_array.size/512)
|
191 |
+
x_array = x_array.reshape(received_samples,512)
|
192 |
+
x_array = np.asarray(x_array)
|
193 |
+
|
194 |
+
# step-3: cal. mean embeddings
|
195 |
+
x_mean = x_array.mean(axis=0)
|
196 |
+
x_mean = x_mean.astype(np.float32)
|
197 |
+
x_mean_bytes = x_mean.tobytes()
|
198 |
+
|
199 |
+
# step-4: save this into redis database
|
200 |
+
# redis hashes
|
201 |
+
r.hset(name='academy:register',key=key,value=x_mean_bytes)
|
202 |
+
|
203 |
+
#
|
204 |
+
os.remove('face_embedding.txt')
|
205 |
+
self.reset()
|
206 |
+
|
207 |
+
return True
|