forked from oarriaga/face_classification
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request oarriaga#16 from ekholabs/master
Dockerize the project and add a RESTful service to process images
- Loading branch information
Showing
5 changed files
with
153 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
FROM debian:latest | ||
|
||
RUN apt-get -y update && apt-get install -y git python3-pip python3-dev python3-tk vim procps curl | ||
|
||
#Face classificarion dependencies & web application | ||
RUN pip3 install numpy scipy scikit-learn pillow tensorflow pandas h5py opencv-python==3.2.0.8 keras statistics pyyaml pyparsing cycler matplotlib Flask | ||
|
||
ADD . /ekholabs/face-classifier | ||
|
||
WORKDIR ekholabs/face-classifier | ||
|
||
ENV PYTHONPATH=$PYTHONPATH:src | ||
ENV FACE_CLASSIFIER_PORT=8084 | ||
EXPOSE $FACE_CLASSIFIER_PORT | ||
|
||
ENTRYPOINT ["python3"] | ||
CMD ["src/web/faces.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import os | ||
import sys | ||
import logging | ||
|
||
import cv2 | ||
from keras.models import load_model | ||
import numpy as np | ||
|
||
from utils.datasets import get_labels | ||
from utils.inference import detect_faces | ||
from utils.inference import draw_text | ||
from utils.inference import draw_bounding_box | ||
from utils.inference import apply_offsets | ||
from utils.inference import load_detection_model | ||
from utils.inference import load_image | ||
from utils.preprocessor import preprocess_input | ||
|
||
def process_image(image): | ||
|
||
try: | ||
# parameters for loading data and images | ||
detection_model_path = './trained_models/detection_models/haarcascade_frontalface_default.xml' | ||
emotion_model_path = './trained_models/emotion_models/fer2013_mini_XCEPTION.102-0.66.hdf5' | ||
gender_model_path = './trained_models/gender_models/simple_CNN.81-0.96.hdf5' | ||
emotion_labels = get_labels('fer2013') | ||
gender_labels = get_labels('imdb') | ||
font = cv2.FONT_HERSHEY_SIMPLEX | ||
|
||
# hyper-parameters for bounding boxes shape | ||
gender_offsets = (30, 60) | ||
gender_offsets = (10, 10) | ||
emotion_offsets = (20, 40) | ||
emotion_offsets = (0, 0) | ||
|
||
# loading models | ||
face_detection = load_detection_model(detection_model_path) | ||
emotion_classifier = load_model(emotion_model_path, compile=False) | ||
gender_classifier = load_model(gender_model_path, compile=False) | ||
|
||
# getting input model shapes for inference | ||
emotion_target_size = emotion_classifier.input_shape[1:3] | ||
gender_target_size = gender_classifier.input_shape[1:3] | ||
|
||
# loading images | ||
image_array = np.fromstring(image, np.uint8) | ||
unchanged_image = cv2.imdecode(image_array, cv2.IMREAD_UNCHANGED) | ||
|
||
rgb_image = cv2.cvtColor(unchanged_image, cv2.COLOR_BGR2RGB) | ||
gray_image = cv2.cvtColor(unchanged_image, cv2.COLOR_BGR2GRAY) | ||
|
||
faces = detect_faces(face_detection, gray_image) | ||
for face_coordinates in faces: | ||
x1, x2, y1, y2 = apply_offsets(face_coordinates, gender_offsets) | ||
rgb_face = rgb_image[y1:y2, x1:x2] | ||
|
||
x1, x2, y1, y2 = apply_offsets(face_coordinates, emotion_offsets) | ||
gray_face = gray_image[y1:y2, x1:x2] | ||
|
||
try: | ||
rgb_face = cv2.resize(rgb_face, (gender_target_size)) | ||
gray_face = cv2.resize(gray_face, (emotion_target_size)) | ||
except: | ||
continue | ||
|
||
rgb_face = preprocess_input(rgb_face, False) | ||
rgb_face = np.expand_dims(rgb_face, 0) | ||
gender_prediction = gender_classifier.predict(rgb_face) | ||
gender_label_arg = np.argmax(gender_prediction) | ||
gender_text = gender_labels[gender_label_arg] | ||
|
||
gray_face = preprocess_input(gray_face, True) | ||
gray_face = np.expand_dims(gray_face, 0) | ||
gray_face = np.expand_dims(gray_face, -1) | ||
emotion_label_arg = np.argmax(emotion_classifier.predict(gray_face)) | ||
emotion_text = emotion_labels[emotion_label_arg] | ||
|
||
if gender_text == gender_labels[0]: | ||
color = (0, 0, 255) | ||
else: | ||
color = (255, 0, 0) | ||
|
||
draw_bounding_box(face_coordinates, rgb_image, color) | ||
draw_text(face_coordinates, rgb_image, gender_text, color, 0, -20, 1, 2) | ||
draw_text(face_coordinates, rgb_image, emotion_text, color, 0, -50, 1, 2) | ||
except Exception as err: | ||
logging.error('Error in emotion gender processor: "{0}"'.format(err)) | ||
|
||
bgr_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2BGR) | ||
|
||
dirname = 'result' | ||
if not os.path.exists(dirname): | ||
os.mkdir(dirname) | ||
|
||
cv2.imwrite(os.path.join(dirname, 'predicted_image.png'), bgr_image) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from flask import Flask, jsonify, make_response, request, abort, redirect, send_file | ||
import logging | ||
|
||
import emotion_gender_processor as eg_processor | ||
|
||
app = Flask(__name__) | ||
|
||
@app.route('/') | ||
def index(): | ||
return redirect("https://ekholabs.ai", code=302) | ||
|
||
@app.route('/classifyImage', methods=['POST']) | ||
def upload(): | ||
try: | ||
image = request.files['image'].read() | ||
eg_processor.process_image(image) | ||
return send_file('/ekholabs/face-classifier/result/predicted_image.png', mimetype='image/png') | ||
except Exception as err: | ||
logging.error('An error has occurred whilst processing the file: "{0}"'.format(err)) | ||
abort(400) | ||
|
||
@app.errorhandler(400) | ||
def bad_request(erro): | ||
return make_response(jsonify({'error': 'We cannot process the file sent in the request.'}), 400) | ||
|
||
@app.errorhandler(404) | ||
def not_found(error): | ||
return make_response(jsonify({'error': 'Resource no found.'}), 404) | ||
|
||
if __name__ == '__main__': | ||
app.run(debug=True, host='0.0.0.0', port=8084) |