-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.py
375 lines (267 loc) · 9.03 KB
/
run.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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
"""
Importing necessary libraries
cv2 - OpenCV for image proceesing and recognition
time - for speed comparisons of classifiers/recognizers
os - for reading training data directories and path
numpy - to convertToRGB python lists to numpy arrays as parameter to OpenCV face recognizers
Flask - getting associated functions needed for routing and rendering
"""
import cv2
import time
import os
import numpy as np
from flask import Flask, render_template, jsonify, request, redirect, url_for
from pymongo import MongoClient
import gridfs
conn = MongoClient("localhost", 27017)
db = conn.gridfs_test
fs = gridfs.GridFS(db)
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
app = Flask(__name__)
haar_face_cascade_frontal = cv2.CascadeClassifier('./classifiers/haarcascade_frontalface_alt.xml')
haar_face_cascade_profile = cv2.CascadeClassifier('./classifiers/haarcascade_profileface.xml')
haar_face_cascade = [haar_face_cascade_profile, haar_face_cascade_frontal]
subjects = ["", "Arvind Kejriwal", "Narendra Modi", "None"]
print("Preparing data...")
def allowed_file(filename):
"""
purpoose:
filters file name for only acceptable extenstions that identify an image
args:
filename - name of the file that will be read
returns:
boolean indicating whether the file name and thereby the file is an acceptable image or not
"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET', 'POST'])
def upload_image():
"""
purpoose:
flask function that serve as the first route for the web application
args:
None
returns:
renders the preliminary home page which is the file upload form for the images
"""
if request.method == 'POST':
if 'file' not in request.files:
return redirect(request.url)
file = request.files['file']
if file.filename == '':
return redirect(request.url)
if file and allowed_file(file.filename):
return detect_faces_in_image(file)
return render_template('index.html', data={})
def detect_faces_in_image(file_stream):
"""
purpoose:
intermediate function that loads the uploaded image and
routes to the face recognition function and renders the
results returned back from the same
args:
file_stream - the uploaded iamge file
returns:
renders the resultant web page with the results of the
face recognition in addition to the upload form
"""
img = cv2.imdecode(np.fromstring(file_stream.read(), np.uint8), cv2.IMREAD_COLOR)
predicted_img, result = predict(img)
print result
print("Prediction complete")
cv2.imwrite('./static/Predicted Image.jpeg',predicted_img)
return render_template('index.html', data=result)
def convertToRGB(img):
"""
purpose:
re-colors the grayscale image for display
args:
img - loaded image
returns:
colorized image as output
"""
return cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
def detect_faces(f_cascade, colored_img, scaleFactor = 1.2):
"""
purpoose:
manipulates a grayscale copy of the image and detects multiscale
(some images may be closer to camera than others) images and draws
the faces as rectangles on the original image
args:
f_cascade - a list containing the classifiers loaded for
face detection
colored_img - the uploaded image
scaleFactor - factor of reduction to deal with multiscale
images
returns:
found_faces - a list containg tuples of the form (img_section, dim)
where,
img_section - grayscale section of the image
where the face has been detected
dim - the co-ordinate dimensions where
the face has been detected
if no faces are found, it returns the original image as a result
"""
img_copy = colored_img.copy()
gray = cv2.cvtColor(img_copy, cv2.COLOR_BGR2GRAY)
faces = []
for classifier in f_cascade:
face = classifier.detectMultiScale(gray, scaleFactor=scaleFactor, minNeighbors=5)
if face != ():
faces.append(face)
# the number of faces found
# print('Faces found: ', len(faces))
if (faces == []):
return None, None
found_faces = []
for face in faces:
for f in face:
(x, y, w, h) = f
cv2.rectangle(img_copy, (x, y), (x+w, y+h), (0, 255, 0), 2)
found_faces.append((gray[y:y+w, x:x+h], [x, y, w, h]))
return found_faces
def prepare_training_data(data_folder_path):
"""
purpoose:
this functions detects and learns from faces from all the
training images of each person (subject) and returns the
faces mapped with the label (the person's identification)
args:
data_folder_path - the path to the directory that holds
all the training images
returns:
faces - list of all faces detected in all images
labels - corresponding labels for the respective
faces so as to tag them
"""
dirs = os.listdir(data_folder_path)
faces = []
labels = []
for dir_name in dirs:
label = int(dir_name)
subject_dir_path = data_folder_path + "/" + dir_name
subject_images_names = os.listdir(subject_dir_path)
for image_name in subject_images_names:
image_path = subject_dir_path + "/" + image_name
image = cv2.imread(image_path)
# Display image that is being trained
# cv2.imshow("Training on image...", image)
# cv2.waitKey(100)
found_faces = detect_faces(haar_face_cascade, image)
if found_faces != (None, None):
for found_face in found_faces:
face, rect = found_face
faces.append(face)
labels.append(label)
else:
# print(image_name) # if no face is found in the image
continue
# cv2.destroyAllWindows()
# cv2.waitKey(1)
# cv2.destroyAllWindows()
return faces, labels
def draw_rectangle(img, rect):
"""
purpose:
draws a rectangle on the image given the (x, y) coordinates,
the width and the height
args:
img - the image on which the rectangle overlay has to
be drawn
rect - the dimensions of the detected face, namely the
(x, y) coorinates for the corner, the width, and
the height of the rectangle to be drawn
returns:
None
"""
(x, y, w, h) = rect
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
def draw_text(img, text, x, y):
"""
purpose:
adds the label (name of the person) to the image given the
(x, y) coordinates
args:
img - the image on which the label has to be added
text - the label of the identified person
x,y - the co-ordinates of the starting point for the
text to be added
returns:
None
"""
cv2.putText(img, text, (x, y), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1)
faces, labels = prepare_training_data("./data/training-data")
print("Data prepared")
# Print total faces and labels that are detected and read in the training data
# print("Total faces: ", len(faces))
# print("Total labels: ", len(labels))
face_recognizer = cv2.face.LBPHFaceRecognizer_create()
# Alternative recognizers
# face_recognizer = cv2.face.createEigenFaceRecognizer()
# face_recognizer = cv2.face.createFisherFaceRecognizer()
face_recognizer.train(faces, np.array(labels))
def predict(test_img):
"""
purpose:
to leverage the recognizers to detect and identify the people
whose faces are present in the uploaded image
args:
img - the image on which the label has to be added
text - the label of the identified person
x,y - the co-ordinates of the starting point for the
text to be added
returns:
None
"""
img = test_img.copy()
found_faces = detect_faces(haar_face_cascade, img)
face_found = "No"
is_modi = "No"
is_kejri = "No"
if len(found_faces) > 0 and found_faces != (None, None):
face_found = "Yes"
for found_face in found_faces:
face, rect = found_face
label= face_recognizer.predict(face)
label_text = subjects[label[0]]
draw_rectangle(img, rect)
# Add name of the predicted person
# draw_text(img, label_text, rect[0], rect[1]-5)
if label[1] > 100:
continue
if label_text == "Narendra Modi":
is_modi = "Yes"
if label_text == "Arvind Kejriwal":
is_kejri = "Yes"
result = {
"face_found_in_image": face_found,
"is_picture_of_modi": is_modi,
"is_picture_of_kejri": is_kejri
}
return img, result
@app.after_request
def add_header(response):
"""
Adding headers to both force latest IE rendering engine or Chrome Frame,
and also to cache the rendered page for 10 minutes.
"""
response.headers['X-UA-Compatible'] = 'IE=Edge,chrome=1'
response.headers['Cache-Control'] = 'public, max-age=0'
return response
"""
# Manual Testing one image:
# Detecting a face:
test = cv2.imread('./data/both_1.jpeg')
faces_detected_img = detect_faces(haar_face_cascade, test2)
plt.imshow(convertToRGB(faces_detected_img))
plt.show()
----------------------------------------------------------
# Recognizing a face:
test_img1 = cv2.imread("./data/test-data/both_6.jpeg")
predicted_img1 = predict(test_img1)
print("Prediction complete")
cv2.imshow(subjects[1], predicted_img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
"""
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5001, debug=True)