-
Notifications
You must be signed in to change notification settings - Fork 72
/
facerec_service.py
154 lines (114 loc) · 4.6 KB
/
facerec_service.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
from os import listdir, remove
from os.path import isfile, join, splitext
import face_recognition
from flask import Flask, jsonify, request
from flask_cors import CORS
from werkzeug.exceptions import BadRequest
# Global storage for images
faces_dict = {}
persistent_faces = "/root/faces"
# Create flask app
app = Flask(__name__)
CORS(app)
# <Picture functions> #
def is_picture(filename):
image_extensions = {'png', 'jpg', 'jpeg', 'gif'}
return '.' in filename and filename.rsplit('.', 1)[1].lower() in image_extensions
def get_all_picture_files(path):
files_in_dir = [join(path, f) for f in listdir(path) if isfile(join(path, f))]
return [f for f in files_in_dir if is_picture(f)]
def remove_file_ext(filename):
return splitext(filename.rsplit('/', 1)[-1])[0]
def calc_face_encoding(image):
# Currently only use first face found on picture
loaded_image = face_recognition.load_image_file(image)
faces = face_recognition.face_encodings(loaded_image)
# If more than one face on the given image was found -> error
if len(faces) > 1:
raise Exception(
"Found more than one face in the given training image.")
# If none face on the given image was found -> error
if not faces:
raise Exception("Could not find any face in the given training image.")
return faces[0]
def get_faces_dict(path):
image_files = get_all_picture_files(path)
return dict([(remove_file_ext(image), calc_face_encoding(image))
for image in image_files])
def detect_faces_in_image(file_stream):
# Load the uploaded image file
img = face_recognition.load_image_file(file_stream)
# Get face encodings for any faces in the uploaded image
uploaded_faces = face_recognition.face_encodings(img)
# Defaults for the result object
faces_found = len(uploaded_faces)
faces = []
if faces_found:
face_encodings = list(faces_dict.values())
for uploaded_face in uploaded_faces:
match_results = face_recognition.compare_faces(
face_encodings, uploaded_face)
for idx, match in enumerate(match_results):
if match:
match = list(faces_dict.keys())[idx]
match_encoding = face_encodings[idx]
dist = face_recognition.face_distance([match_encoding],
uploaded_face)[0]
faces.append({
"id": match,
"dist": dist
})
return {
"count": faces_found,
"faces": faces
}
# <Picture functions> #
# <Controller>
@app.route('/', methods=['POST'])
def web_recognize():
file = extract_image(request)
if file and is_picture(file.filename):
# The image file seems valid! Detect faces and return the result.
return jsonify(detect_faces_in_image(file))
else:
raise BadRequest("Given file is invalid!")
@app.route('/faces', methods=['GET', 'POST', 'DELETE'])
def web_faces():
# GET
if request.method == 'GET':
return jsonify(list(faces_dict.keys()))
# POST/DELETE
file = extract_image(request)
if 'id' not in request.args:
raise BadRequest("Identifier for the face was not given!")
if request.method == 'POST':
app.logger.info('%s loaded', file.filename)
# HINT jpg included just for the image check -> this is faster then passing boolean var through few methods
# TODO add method for extension persistence - do not forget abut the deletion
file.save("{0}/{1}.jpg".format(persistent_faces, request.args.get('id')))
try:
new_encoding = calc_face_encoding(file)
faces_dict.update({request.args.get('id'): new_encoding})
except Exception as exception:
raise BadRequest(exception)
elif request.method == 'DELETE':
faces_dict.pop(request.args.get('id'))
remove("{0}/{1}.jpg".format(persistent_faces, request.args.get('id')))
return jsonify(list(faces_dict.keys()))
def extract_image(request):
# Check if a valid image file was uploaded
if 'file' not in request.files:
raise BadRequest("Missing file parameter!")
file = request.files['file']
if file.filename == '':
raise BadRequest("Given file is invalid")
return file
# </Controller>
if __name__ == "__main__":
print("Starting by generating encodings for found images...")
# Calculate known faces
faces_dict = get_faces_dict(persistent_faces)
print(faces_dict)
# Start app
print("Starting WebServer...")
app.run(host='0.0.0.0', port=8080, debug=False)