├── .gitignore ├── README.md ├── app.py ├── detect_face.py ├── example ├── haarcascade_frontalface_default.xml ├── requirements.txt └── zappa_settings.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zappa_resize_image_on_fly 2 | 3 | Resize image on the fly using flask, zappa, pillow, opencv-python 4 | 5 | you can change the width, height and image type on the fly 6 | 7 | usage `/image/full/{width pixels}x{height pixels}.{extension}` 8 | 9 | usage for face box resize `/image/face/{width pixels}x{height pixels}.{extension}` 10 | 11 | examples: 12 | 13 | https://jyhmaij1l4.execute-api.us-east-1.amazonaws.com/dev/image/example/200x200.jpg 14 | 15 | https://jyhmaij1l4.execute-api.us-east-1.amazonaws.com/dev/image/example/350x350.png -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import os 2 | from PIL import Image 3 | from flask import Flask, send_file 4 | from flask import make_response 5 | from io import BytesIO 6 | 7 | from detect_face import detect_face 8 | 9 | app = Flask(__name__) 10 | 11 | dir_path = os.path.dirname(os.path.realpath(__file__)) 12 | pic_path = os.path.join(dir_path, 'example') 13 | 14 | 15 | @app.route('/example') 16 | def example(): 17 | """Serves raw image image.""" 18 | with open(os.path.join(dir_path, 'example'), 'rb') as bites: 19 | return send_file(BytesIO(bites.read()), 20 | attachment_filename='example.jpg', 21 | mimetype='image/jpg') 22 | 23 | 24 | @app.route('/image//x.', methods=['GET']) 25 | def image(face_only, width, height, ext, name=pic_path): 26 | """Serves image image according to params.""" 27 | 28 | face_box = detect_face(name) 29 | img = Image.open(name) 30 | if face_box and face_only == 'face': 31 | img2 = img.crop(face_box) 32 | img = img2 33 | 34 | if width == 0 and height != 0: 35 | hpercent = (height / float(img.size[1])) 36 | width = int((float(img.size[0]) * float(hpercent))) 37 | elif width != 0 and height == 0: 38 | wpercent = (width / float(img.size[0])) 39 | height = int((float(img.size[1]) * float(wpercent))) 40 | elif width == 0 and height == 0: 41 | width = img.size[0] 42 | height = img.size[1] 43 | 44 | img = img.resize((width, height), Image.ANTIALIAS) 45 | 46 | buffer = BytesIO() 47 | image_format = "jpeg" if ext == "jpg" else ext 48 | img.save(buffer, format=image_format.capitalize()) 49 | 50 | response = make_response(buffer.getvalue()) 51 | response.headers['Content-Type'] = "image/" + ext 52 | return response 53 | 54 | 55 | if __name__ == "__main__": 56 | app.run(host='0.0.0.0') 57 | -------------------------------------------------------------------------------- /detect_face.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from cv2.cv2 import CascadeClassifier, imread 4 | 5 | 6 | def detect_face(image_path): 7 | # Get user supplied values 8 | casc_path = os.path.join(os.path.dirname(__file__), "haarcascade_frontalface_default.xml") 9 | 10 | # Create the haar cascade 11 | face_cascade = CascadeClassifier(casc_path) 12 | 13 | # Read the image as greyscale 14 | gray = imread(image_path, 0) 15 | 16 | # Detect faces in the image 17 | faces = face_cascade.detectMultiScale( 18 | gray, 19 | scaleFactor=1.1, 20 | minNeighbors=5, 21 | minSize=(30, 30) 22 | # flags = cv2.CV_HAAR_SCALE_IMAGE 23 | ) 24 | 25 | for (x, y, w, h) in faces: 26 | y = y - (h * 0.3) 27 | h = h * 1.6 28 | x = x - (w * 0.3) 29 | w = w * 1.6 30 | return x, y, x + w, y + h 31 | 32 | return None 33 | -------------------------------------------------------------------------------- /example: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wobeng/zappa_resize_image_on_fly/e561f65211ba8846c1b4769dba9352ef1ab5e25d/example -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | Pillow 3 | opencv-python 4 | Zappa 5 | -------------------------------------------------------------------------------- /zappa_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": { 3 | "app_function": "app.app", 4 | "s3_bucket": "", 5 | "binary_support": true, 6 | "exclude": [ 7 | ".*", 8 | "*.sh" 9 | ] 10 | } 11 | } --------------------------------------------------------------------------------