pranav-5644 commited on
Commit
00f8748
1 Parent(s): 5f7891e

added initial files

Browse files
Files changed (7) hide show
  1. abc1.jpg +0 -0
  2. abc2.jpg +0 -0
  3. app.py +32 -0
  4. description.md +18 -0
  5. embeddings.pkl +3 -0
  6. friends.zip +3 -0
  7. processing.py +247 -0
abc1.jpg ADDED
abc2.jpg ADDED
app.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from PIL import Image
3
+ from processing import process_image, generate_embeddings , recognize_faces
4
+
5
+ def driver(image,zip_file,date):
6
+ image.save('class_attendance.jpg')
7
+ fig = process_image('class_attendance.jpg')
8
+ generate_embeddings(zip_file)
9
+ recognize_faces("embeddings.pkl",date)
10
+ file_name = f"{date}.txt"
11
+
12
+ with open(file_name, 'r') as file:
13
+ content = file.read()
14
+ image_detected = Image.open('image_detected.jpg')
15
+ image_grid = Image.open('image_grid.jpg')
16
+ return file_name,image_detected,image_grid
17
+
18
+ # Define the Gradio interface
19
+ # Read the content of the .md file
20
+ with open("description.md", "r") as file:
21
+ description_text = file.read()
22
+
23
+ demo = gr.Interface(
24
+ fn=driver,
25
+ inputs=[gr.Image(label="Upload the image of group/class",type="pil"),gr.File(label="Upload ZIP file containing images of students/employees"),gr.Textbox(label="enter date")],
26
+ outputs=[gr.File(label="Download Attendance File"),gr.Image(label="Image with face detections"),"image"],
27
+ title="Automated Attendance System",
28
+ description=description_text,
29
+ examples=[["abc1.jpg","friends.zip","01-03-2005"],["abc2.jpg","friends.zip","10-04-2006"]],
30
+ article="<b>if you find any unexpected or wrong results please flag them so that we can improve our model for those type of inputs.<b>"
31
+ )
32
+ demo.launch(share=False,inline=False)
description.md ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ You have to just provide a group photo with a zip file (containing the images of people to be recognized in the below mentioned format).<br>
2
+ The software would automatically detect all the people present in the group photo.<br>
3
+ Inside the zip archive, include only image files. The images should be named in a specific format, such as<br>
4
+ - person1.jpg,
5
+ - person2.jpg,
6
+ - person3.jpg,
7
+ - etc.
8
+
9
+ **Format for the zip file :**
10
+
11
+ ```plaintext
12
+ train.zip/
13
+ person1.jpg
14
+ person2.jpg
15
+ person3.jpg
16
+ ...
17
+ ```
18
+ **Please refer to the examples given below to understand the input.**
embeddings.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9d0cd7d29209df0875b951bd8061cf5a6d00a282caac52e96e0fbf434ee6cee9
3
+ size 50353
friends.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:20a0c7f6067b905ae87a43e3d9629916dff7db3a195757decfe08c4eb8266bcc
3
+ size 30296
processing.py ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # firstly import the necessary libraries :
2
+ import cv2
3
+ import matplotlib.pyplot as plt
4
+ import numpy as np
5
+ import os
6
+ import zipfile
7
+ from os import listdir
8
+ from PIL import Image
9
+ from numpy import asarray,expand_dims
10
+ from matplotlib import pyplot
11
+ from keras.models import load_model
12
+ from keras_facenet import FaceNet
13
+ import pickle
14
+ from mtcnn import MTCNN
15
+ import math
16
+
17
+ # we are going to use harr cacade first
18
+ HaarCascade = cv2.CascadeClassifier(cv2.samples.findFile(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'))
19
+ # if harr cascade is unable to detect we will keep mtcnn for that case
20
+ # Initialize the MTCNN detector
21
+ mtcnn = MTCNN()
22
+ # we are going to use Facenet architecture for creating the embeddings from faces
23
+ model_face = FaceNet()
24
+
25
+
26
+ def process_image(image_path):
27
+ image = cv2.imread(image_path,cv2.IMREAD_UNCHANGED)
28
+ # for this example we are not resizing the image dimensions :
29
+ resized=image
30
+ image_rgb = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
31
+
32
+ # we need to adjust the size of window in cv 2 to display the image
33
+
34
+
35
+ face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
36
+ gray_image = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
37
+ faces = face_cascade.detectMultiScale(gray_image, scaleFactor=1.1, minNeighbors=5)
38
+
39
+ cv2.namedWindow("output", cv2.WINDOW_NORMAL)
40
+ cv2.resizeWindow("output", resized.shape[0],resized.shape[1])
41
+ for (x, y, w, h) in faces:
42
+ cv2.rectangle(image_rgb, (x, y), (x+w, y+h), (0, 255, 0), 2)
43
+ cv2.imshow("output", image_rgb)
44
+ # cv2.waitKey(0)
45
+ cv2.destroyAllWindows()
46
+
47
+ # convert the image back to RGB format and adjust the brighness and contrast after processing
48
+
49
+ final = cv2.cvtColor(image_rgb, cv2.COLOR_BGR2RGB)
50
+ final = cv2.convertScaleAbs(final, alpha=1, beta=0) # Adjust alpha and beta as needed
51
+
52
+ # save the image with bounding boxes as image_detected.jpg
53
+ cv2.imwrite('image_detected.jpg',final)
54
+
55
+ folder_name = 'attendance_folder'
56
+ if not os.path.exists(folder_name):
57
+ os.mkdir(folder_name)
58
+ # List all files in the folder
59
+ file_list = os.listdir(folder_name)
60
+
61
+ face_images = []
62
+
63
+ # Iterate through the files and remove them
64
+ for file in file_list:
65
+ file_path = os.path.join(folder_name, file)
66
+ if os.path.isfile(file_path):
67
+ os.remove(file_path)
68
+
69
+ # Save the cropped photos in the folder named attendance_class
70
+ for (x, y, w, h) in faces:
71
+ face_crop = resized[y:y+h, x:x+w]
72
+ face_images.append(face_crop)
73
+ face_filename = os.path.join(folder_name, f'face_{x}_{y}.jpg')
74
+ cv2.imwrite(face_filename, face_crop)
75
+
76
+
77
+ # we need to adjust the size of window in cv 2 to display the image
78
+ # folder_name = 'attendance_folder'
79
+ # if not os.path.exists(folder_name):
80
+ # os.mkdir(folder_name)
81
+ # List all files in the folder
82
+ # file_list = os.listdir(folder_name)
83
+
84
+ # face_images = []
85
+
86
+ # # Iterate through the files and remove them
87
+ # for file in file_list:
88
+ # file_path = os.path.join(folder_name, file)
89
+ # if os.path.isfile(file_path):
90
+ # os.remove(file_path)
91
+
92
+ # cv2.namedWindow("output", cv2.WINDOW_NORMAL)
93
+ # cv2.resizeWindow("output", resized.shape[0],resized.shape[1])
94
+
95
+ # for face in faces:
96
+ # x, y, w, h = face['box']
97
+ # cv2.rectangle(image_rgb, (x, y), (x+w, y+h), (0, 255, 0), 2)
98
+ # cv2.imshow("output", image_rgb)
99
+ # # cv2.waitKey(0)
100
+ # face_crop = resized[y:y+h, x:x+w]
101
+ # face_images.append(face_crop)
102
+ # face_filename = os.path.join(folder_name, f'face_{x}_{y}.jpg')
103
+ # cv2.imwrite(face_filename, face_crop)
104
+ # cv2.destroyAllWindows()
105
+
106
+ # # convert the image back to RGB format and adjust the brighness and contrast after processing
107
+
108
+ # final = cv2.cvtColor(image_rgb, cv2.COLOR_BGR2RGB)
109
+ # final = cv2.convertScaleAbs(final, alpha=1, beta=0) # Adjust alpha and beta as needed
110
+
111
+ # # save the image with bounding boxes as image_detected.jpg
112
+ # cv2.imwrite('image_detected.jpg',final)
113
+
114
+
115
+ def intermediate_process(gbr1):
116
+ # detect the face in the cropped photo :
117
+ harr = HaarCascade.detectMultiScale(gbr1,1.1,4)
118
+
119
+ # if the face is detected then get the width and height
120
+ if len(harr)>0:
121
+ x1, y1, width, height = harr[0]
122
+
123
+ # if harr cascade is unable to detect the face use mtcnn
124
+ else:
125
+ faces_mtcnn = mtcnn.detect_faces(gbr1)
126
+ if len(faces_mtcnn)>0:
127
+ x1, y1, width, height = faces_mtcnn[0]['box']
128
+ else :
129
+ # if no face is detected in the image just use the top left 10x10 pixels
130
+ x1, y1, width, height = 1, 1, 10, 10
131
+
132
+
133
+ x1, y1 = abs(x1), abs(y1)
134
+ x2, y2 = x1 + width, y1 + height
135
+
136
+ #convert from bgr to rgb
137
+ gbr = cv2.cvtColor(gbr1, cv2.COLOR_BGR2RGB)
138
+ gbr = Image.fromarray(gbr) # Convert from OpenCV to PIL
139
+ # convert image as numpy array
140
+ gbr_array = asarray(gbr)
141
+
142
+ # crop the face , resize it and store in face
143
+ face = gbr_array[y1:y2, x1:x2]
144
+ face = Image.fromarray(face)
145
+ face = face.resize((160, 160))
146
+ face = asarray(face)
147
+ return gbr, face
148
+
149
+
150
+ def generate_embeddings(zip_path):
151
+
152
+ folder_name = os.path.splitext(zip_path)[0]
153
+
154
+ # Create the directory if it does not exist
155
+ if not os.path.exists(folder_name):
156
+ os.makedirs(folder_name)
157
+
158
+ # Unzip the file
159
+ with zipfile.ZipFile(zip_path, 'r') as zip_ref:
160
+ zip_ref.extractall(folder_name)
161
+ folder=folder_name+'/'
162
+ # now generate the embeddings :
163
+ # intialize empty dictionary in which we will store the embeddings with name of the person
164
+ database = {}
165
+
166
+ # iterate through all the images in the training images folder
167
+ for filename in listdir(folder):
168
+ path = folder + filename
169
+ gbr1 = cv2.imread(folder + filename)
170
+
171
+ gbr, face = intermediate_process(gbr1)
172
+
173
+ # facenet takes as input 4 dimensional array so we expand dimension
174
+ face = expand_dims(face, axis=0)
175
+ signature = model_face.embeddings(face)
176
+
177
+ # store the array in the database
178
+ database[os.path.splitext(filename)[0]] = signature
179
+
180
+ cv2.destroyAllWindows()
181
+ # make a file named data_processed.pkl and store the database in it
182
+ myfile = open("embeddings.pkl", "wb")
183
+ pickle.dump(database, myfile)
184
+ myfile.close()
185
+
186
+ def recognize_faces(embeddigns_path,date):
187
+ myfile = open(embeddigns_path, "rb")
188
+ database = pickle.load(myfile)
189
+ myfile.close()
190
+ # same procedure as training
191
+ folder = 'attendance_folder/'
192
+ file_list = os.listdir(folder)
193
+ predicted=[]
194
+ # Set up the plot
195
+ num_images = len(file_list)
196
+ num_rows = math.ceil(num_images / 4) if math.ceil(num_images / 4)>0 else 1 # Ceiling division to calculate the number of rows
197
+ fig, axes = plt.subplots(num_rows, 4, figsize=(16, 4*num_rows))
198
+ if(num_rows==1):
199
+ axes=axes.reshape(1,4)
200
+ for i,filename in enumerate(file_list):
201
+ path = os.path.join(folder, filename)
202
+ gbr1 = cv2.imread(folder + filename)
203
+
204
+ gbr,face = intermediate_process(gbr1)
205
+
206
+ face = expand_dims(face, axis=0)
207
+ signature = model_face.embeddings(face)
208
+
209
+ min_dist=100
210
+ identity=' '
211
+ for key, value in database.items() :
212
+ dist = np.linalg.norm(value-signature)
213
+ if dist < min_dist:
214
+ min_dist = dist
215
+ identity = key
216
+ # Plot the image with the identity text
217
+ row = i // 4
218
+ col = i % 4
219
+ axes[row, col].imshow(gbr)
220
+ axes[row, col].set_title(f"Identity: {identity}", fontsize=25)
221
+ axes[row, col].axis('off')
222
+ # print(identity)
223
+ # cv2.namedWindow("output", cv2.WINDOW_NORMAL)
224
+ # cv2.resizeWindow("output", gbr1.shape[0],gbr1.shape[1])
225
+ # cv2.putText(gbr1,identity, (100,100),cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 2, cv2.LINE_AA)
226
+ # cv2.rectangle(gbr1,(x1,y1),(x2,y2), (0,255,0), 2)
227
+ # cv2.imshow("output",gbr1)
228
+ # cv2.waitKey(0)
229
+ predicted.append(identity)
230
+ # Hide any remaining empty subplots
231
+ for i in range(num_images, num_rows * 4):
232
+ row = i // 4
233
+ col = i % 4
234
+ axes[row, col].axis('off')
235
+
236
+ plt.tight_layout()
237
+ fig.savefig('image_grid.jpg')
238
+
239
+ cv2.destroyAllWindows()
240
+ # store the name of people present in a text file
241
+ attendance = [name for name in predicted if name != 'unknown']
242
+
243
+ file_name = f"{date}.txt"
244
+
245
+ with open(file_name, 'w') as file:
246
+ for item in attendance:
247
+ file.write(str(item) + '\n')