├── .gitignore ├── Dockerfile ├── LICENSE ├── Procfile ├── README.md ├── __pycache__ └── config.cpython-36.pyc ├── api ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ ├── face_api.cpython-36.pyc │ └── static_api.cpython-36.pyc ├── face_api.py └── static_api.py ├── config.py ├── flask_app ├── __init__.py ├── __init__.pyc ├── __pycache__ │ └── __init__.cpython-36.pyc ├── static │ ├── __init__.py │ ├── index.js │ └── output_image.jpg └── templates │ └── index.html ├── requirements.txt ├── run.py ├── sample.gif └── utils ├── __init__.py ├── __pycache__ ├── __init__.cpython-36.pyc ├── __init__.cpython-37.pyc ├── face.cpython-36.pyc ├── face.cpython-37.pyc ├── read_io.cpython-36.pyc └── read_io.cpython-37.pyc ├── face.py └── read_io.py /.gitignore: -------------------------------------------------------------------------------- 1 | /env 2 | .idea -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6-slim-stretch 2 | 3 | RUN apt-get -y update 4 | RUN apt-get install -y --fix-missing \ 5 | build-essential \ 6 | cmake \ 7 | gfortran \ 8 | git \ 9 | wget \ 10 | curl \ 11 | graphicsmagick \ 12 | libgraphicsmagick1-dev \ 13 | libatlas-base-dev \ 14 | libavcodec-dev \ 15 | libavformat-dev \ 16 | libgtk2.0-dev \ 17 | libjpeg-dev \ 18 | liblapack-dev \ 19 | libswscale-dev \ 20 | pkg-config \ 21 | python3-dev \ 22 | python3-numpy \ 23 | software-properties-common \ 24 | zip \ 25 | && apt-get clean && rm -rf /tmp/* /var/tmp/* 26 | 27 | RUN cd ~ && \ 28 | mkdir -p dlib && \ 29 | git clone -b 'v19.9' --single-branch https://github.com/davisking/dlib.git dlib/ && \ 30 | cd dlib/ && \ 31 | python3 setup.py install --yes USE_AVX_INSTRUCTIONS 32 | 33 | LABEL author="https://sachinkalsi.github.io/" 34 | 35 | COPY . /tmp 36 | WORKDIR /tmp 37 | 38 | VOLUME ["/tmp"] 39 | 40 | RUN pip install --no-cache-dir -r requirements.txt 41 | 42 | CMD ["python", "run.py"] 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Sachin Kalsi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn run:app --log-file=- -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # face-detection-api 2 | 3 | A simple web application built using [Flask](https://github.com/pallets/flask). It exposes various REST APIs which are built on top of [face-recognition](https://github.com/ageitgey/face_recognition). 4 | 5 | # How to execute? 6 | 1. `pip install -r requirements.txt` 7 | 2. `python3 run.py` 8 | 3. visit http://localhost:5000/ 9 | 10 | If not specified the port explicitly, the server starts running on port 5000 by default 11 | 12 | # Use Docker container 13 | Docker image repo: https://hub.docker.com/r/sachinkalsi/face-detection-api 14 | 15 | Run the following commands 16 | 17 | ``` 18 | docker pull sachinkalsi/face-detection-api 19 | 20 | docker run -p 5000:5000 sachinkalsi/face-detection-api 21 | 22 | ``` 23 | 24 | visit http://localhost:5000/ 25 | 26 | 27 | ![](sample.gif) 28 | -------------------------------------------------------------------------------- /__pycache__/config.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/__pycache__/config.cpython-36.pyc -------------------------------------------------------------------------------- /api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/api/__init__.py -------------------------------------------------------------------------------- /api/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/api/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /api/__pycache__/face_api.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/api/__pycache__/face_api.cpython-36.pyc -------------------------------------------------------------------------------- /api/__pycache__/static_api.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/api/__pycache__/static_api.cpython-36.pyc -------------------------------------------------------------------------------- /api/face_api.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, request, jsonify, send_file 2 | from utils.read_io import process_input 3 | # 4 | from utils.face import detect_faces, draw_rect_faces 5 | 6 | 7 | api = Blueprint('api', __name__) 8 | 9 | @api.route('/detect_face', methods=['POST', 'GET']) 10 | def detect_face(): 11 | try: 12 | image_url = process_input(request) 13 | ip = request.remote_addr 14 | face_locations = detect_faces(image_url) 15 | if request.args.get('json'): 16 | return jsonify({ 17 | 'success': True, 18 | 'face_locations': face_locations 19 | }); 20 | draw_rect_faces(face_locations, image_url, ip) 21 | return jsonify({ 22 | 'success': True, 23 | 'image_id': ip, 24 | 'face_count': len(face_locations) 25 | }); 26 | except Exception as e: 27 | return jsonify({ 28 | 'success': False, 29 | 'message': 'Something went wrong ' + str(e) 30 | }); -------------------------------------------------------------------------------- /api/static_api.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, render_template, send_file 2 | 3 | from flask_app import app 4 | static_api = Blueprint('static_api', __name__) 5 | 6 | # @static_api.route('/', methods=['GET']) 7 | # def index(): 8 | # return render_template('index.html') 9 | 10 | @static_api.route('/', methods=['GET']) 11 | def get_image(image_id): 12 | return send_file('static/' +image_id + '.jpg') -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | OUTPUT_PATH = '' 2 | ENV = 'developments' 3 | MAX_CONTENT_LENGTH = 2048 * 1024 # 2MB 4 | INPUT_IMAGE_NAME = 'flask_app/static/input_image.jpg' 5 | OUTPUT_IMAGE_NAME = 'flask_app/static/' -------------------------------------------------------------------------------- /flask_app/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__, instance_relative_config=True) 4 | app.config.from_object('config') -------------------------------------------------------------------------------- /flask_app/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/flask_app/__init__.pyc -------------------------------------------------------------------------------- /flask_app/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/flask_app/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /flask_app/static/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/flask_app/static/__init__.py -------------------------------------------------------------------------------- /flask_app/static/index.js: -------------------------------------------------------------------------------- 1 | 2 | function onSubmit(e) { 3 | e.preventDefault(); 4 | var customMessage = document.getElementById('message'); 5 | if(validateForm(customMessage)) { 6 | uploadImage(customMessage); 7 | } 8 | } 9 | 10 | function get_image_upload_id(){ 11 | return document.getElementById('image-upload'); 12 | } 13 | 14 | function get_image_url(){ 15 | return document.getElementById('image_url') 16 | } 17 | 18 | function validateForm(customMessage) { 19 | const uploadedFile = get_image_upload_id().elements[0].files[0] || get_image_url().value 20 | if(!uploadedFile) { 21 | customMessage.innerHTML = "Please select an image"; 22 | return false; 23 | } 24 | if(typeof(uploadedFile) == 'string'){ 25 | return true; 26 | } 27 | const fileLimit = 2097152; 28 | if(uploadedFile.size > fileLimit) { 29 | customMessage.innerHTML = "Maximum video size allowed: 2MB"; 30 | return false; 31 | } 32 | return true; 33 | } 34 | 35 | function uploadImage(customMessage) { 36 | document.getElementById("submit").disabled = true; 37 | if(get_image_upload_id().elements[0].files[0]){ 38 | customMessage.innerHTML = 'Uploading image...' 39 | return post_request() 40 | } 41 | return get_request() 42 | } 43 | 44 | function post_request(){ 45 | var formElement = get_image_upload_id(); 46 | var request = new XMLHttpRequest(); 47 | request.open("POST", "api/v1/detect_face", true); 48 | request.onload = onComplete; 49 | request.upload.onprogress = fileUploadPercentage; 50 | const data = new FormData(formElement); 51 | request.send(data); 52 | } 53 | 54 | function get_request(){ 55 | var request = new XMLHttpRequest(); 56 | var url = 'api/v1/detect_face?image_url=' + get_image_url().value 57 | request.onload = onComplete; 58 | request.open("GET", url, true); 59 | request.send(); 60 | } 61 | 62 | function onComplete(event) { 63 | var customMessage = document.getElementById('message'); 64 | const response = JSON.parse(event.currentTarget.response); 65 | if(response.success) { 66 | customMessage.style.color = '#9C27B0'; 67 | customMessage.innerHTML = response.face_count + ' faces detected'; 68 | renderDetectedFaces(response.image_id) 69 | } else { 70 | customMessage.innerHTML = "Something went wrong. Cann't identify image file"; 71 | customMessage.style.color = 'red'; 72 | } 73 | document.getElementById("submit").disabled = false; 74 | } 75 | 76 | function renderDetectedFaces(image_id){ 77 | detected_face_image_tag = document.getElementById('output_image') 78 | detected_face_image_tag.src = '/'+image_id+'?'+new Date().getTime(); 79 | document.getElementById("input_image").value = '' 80 | get_image_url().value = '' 81 | detected_face_image_tag.style.display = 'inline' 82 | } 83 | 84 | function fileUploadPercentage(e) { 85 | if (e.lengthComputable) { 86 | var customMessage = document.getElementById('message'); 87 | var percentage = (e.loaded / e.total) * 100; 88 | customMessage.innerHTML = 'Uploading Image: ' + percentage + ' %'; 89 | } 90 | }; 91 | -------------------------------------------------------------------------------- /flask_app/static/output_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/flask_app/static/output_image.jpg -------------------------------------------------------------------------------- /flask_app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Face Detection APIs 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 | 16 |
17 |

OR

18 |
19 | 20 |
21 |
22 | 23 | 24 |
25 |
26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2018.11.29 2 | chardet==3.0.4 3 | Click==7.0 4 | cycler==0.10.0 5 | dlib==19.16.0 6 | face-recognition==1.2.3 7 | face-recognition-models==0.3.0 8 | Flask==1.0.2 9 | gunicorn==19.9.0 10 | idna==2.8 11 | itsdangerous==1.1.0 12 | Jinja2==2.10 13 | kiwisolver==1.0.1 14 | MarkupSafe==1.1.0 15 | matplotlib==3.0.2 16 | numpy==1.15.4 17 | Pillow==8.2.0 18 | pyparsing==2.3.0 19 | python-dateutil==2.7.5 20 | requests==2.21.0 21 | six==1.12.0 22 | urllib3==1.24.2 23 | Werkzeug==0.15.3 24 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | from flask_app import app 2 | from api.face_api import api 3 | from api.static_api import static_api 4 | from flask import render_template 5 | 6 | app.register_blueprint(api, url_prefix='/api/v1') 7 | app.register_blueprint(static_api, url_prefix='/') 8 | 9 | @app.route('/', methods=['GET']) 10 | def index(): 11 | return render_template('index.html') 12 | 13 | if __name__ == '__main__': 14 | app.run(debug=True, host='0.0.0.0') -------------------------------------------------------------------------------- /sample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/sample.gif -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/utils/__init__.py -------------------------------------------------------------------------------- /utils/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/utils/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /utils/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/utils/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /utils/__pycache__/face.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/utils/__pycache__/face.cpython-36.pyc -------------------------------------------------------------------------------- /utils/__pycache__/face.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/utils/__pycache__/face.cpython-37.pyc -------------------------------------------------------------------------------- /utils/__pycache__/read_io.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/utils/__pycache__/read_io.cpython-36.pyc -------------------------------------------------------------------------------- /utils/__pycache__/read_io.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SachinKalsi/face-detection-api/93d012a1b315d3898dbff2612e7beffabdf7d9f7/utils/__pycache__/read_io.cpython-37.pyc -------------------------------------------------------------------------------- /utils/face.py: -------------------------------------------------------------------------------- 1 | import face_recognition 2 | import numpy as np 3 | import matplotlib 4 | matplotlib.use('agg') 5 | import matplotlib.pyplot as plt 6 | import matplotlib.patches as patches 7 | from PIL import Image 8 | from flask_app import app 9 | 10 | def detect_faces(image_url): 11 | image = face_recognition.load_image_file(image_url) 12 | return face_recognition.face_locations(image) 13 | 14 | def draw_rect_faces(face_locations, image_url, ip): 15 | img = np.array(np.array(Image.open(image_url), dtype=np.uint8), dtype=np.uint8) 16 | fig, ax = plt.subplots(figsize=(20, 10)) 17 | ax.imshow(img) 18 | for face_location in face_locations: 19 | top, right, bottom, left = face_location 20 | rect = patches.Rectangle((left, bottom), right - left, top - bottom, linewidth=1, edgecolor='r', 21 | facecolor='none') 22 | ax.add_patch(rect) 23 | ax.set_yticklabels([]) 24 | ax.set_xticklabels([]) 25 | fig.savefig(app.config['OUTPUT_IMAGE_NAME'] + str(ip) + '.jpg', transparent=True) 26 | plt.close(fig) -------------------------------------------------------------------------------- /utils/read_io.py: -------------------------------------------------------------------------------- 1 | from flask_app import app 2 | import requests 3 | 4 | def process_input(request): 5 | ''' 6 | :param requests: request object 7 | :return: processed image url 8 | ''' 9 | image_url = '' 10 | if request.method == 'POST': 11 | image = request.files['image'] 12 | image.save(app.config['INPUT_IMAGE_NAME']) 13 | else: 14 | download_image(request.args.get('image_url')) 15 | return app.config['INPUT_IMAGE_NAME'] 16 | 17 | def download_image(image_url): 18 | r = requests.get(image_url, allow_redirects=True) 19 | open(app.config['INPUT_IMAGE_NAME'], 'wb').write(r.content) --------------------------------------------------------------------------------