From eb8b1c7c6054a9e636bafd178c1d7369610ad2e4 Mon Sep 17 00:00:00 2001 From: Leonardo Aoun Date: Fri, 2 Dec 2022 18:14:18 +0000 Subject: [PATCH 1/4] [docker] Add docker with demo file Add a dockerfile which installs the prereqs. When built and ran, User will automatically enter a tmux session with FAN predicting the Astronaut sklearn image When built and ran, User will automatically enter a tmux session with FAN predicting the Astronaut sklearn image, this behaviour can be changed in future commits. Detector used for now is simply the HaarCascade from opencv. Next steps: - Either build a flask server with UploadImage button, detects the face and draws the landmarks - Or a jupyter notebook with a similar functionality - Script the model, currently I cannot do it because _modules is an issue in HourGlass - I haven't yet tested on GPUs, I believe I need to detect the gpu in bash and pass them using --gpus all --- README.md | 8 ++++++++ demo/Dockerfile | 22 ++++++++++++++++++++++ demo/main.py | 25 +++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 demo/Dockerfile create mode 100644 demo/main.py diff --git a/README.md b/README.md index fbddb78..e299751 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,14 @@ pip install -e . * To test on live video: `python face_alignment_test.py [-i webcam_index]` * To test on a video file: `python face_alignment_test.py [-i input_file] [-o output_file]` +### Docker +You can run a containerized demo using Docker. It will install the needed dependencies and allow you to test the FANPredictor on a sample image. + +`docker build -t ibug-face_alignment -f ./demo/Dockerfile . && docker run -it --rm ibug-face_alignment` +You will automatically enter a tmux session and run demo.py script. If you don't want this, you can either kill it immediately or provide "--entrypoint /bin/bash" to the docker run command. + +Please install Docker using [the official instructions](https://docs.docker.com/get-docker/) + ## How to Use ```python # Import the libraries diff --git a/demo/Dockerfile b/demo/Dockerfile new file mode 100644 index 0000000..d186f1e --- /dev/null +++ b/demo/Dockerfile @@ -0,0 +1,22 @@ +FROM continuumio/miniconda3:4.12.0 + +RUN apt update && apt upgrade -y && \ + apt install -y \ + libgl1 \ + lsof \ + tmux \ + vim + +WORKDIR /face_alignment + +COPY ../requirements.txt . +RUN pip install -r requirements.txt && \ + pip install scikit-image + +COPY ../setup.py . +COPY ../ibug ibug +RUN pip install -e . + +COPY demo/main.py . + +CMD ["tmux", "new-session", "/bin/bash", ";", "new-window", "python -i main.py"] diff --git a/demo/main.py b/demo/main.py new file mode 100644 index 0000000..1a1110f --- /dev/null +++ b/demo/main.py @@ -0,0 +1,25 @@ +import os +import cv2 +import torch +from ibug.face_alignment import FANPredictor +from skimage.data import astronaut +import numpy as np + +image = astronaut() +gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) +face_cascade = cv2.CascadeClassifier(os.path.join(cv2.data.haarcascades, "haarcascade_frontalface_default.xml")) +detections = face_cascade.detectMultiScale(gray) +assert len(detections) == 1, "Please submit an image with exactly one clear frontal face" +x, y, w, h = detections[0] +detection = np.array([x, y, x+w, y+h]) + + + +config = FANPredictor.create_config(gamma = 1.0, radius = 0.1, use_jit = False) + +device = "cpu" +if torch.cuda.is_available(): + device = torch.cuda.current_device() +fan = FANPredictor(device=device, model=FANPredictor.get_model('2dfan2_alt'), config=config) + +landmarks, scores = fan(image, detection) From 586041dddd0c2368f12793444a65067376de7686 Mon Sep 17 00:00:00 2001 From: Leonardo Aoun Date: Sat, 3 Dec 2022 16:08:10 +0000 Subject: [PATCH 2/4] [docker] test on windows and add instructions Still not able to run on GPU but it's not a huge issue as demoing seems fine on a CPU, it takes .3 secs per image. Might not work for all versions of windows or environments, but I guess it's a working progress. Next steps: - Add the jupyter notebook demo - Figure out how to pull RetinaFace. --- README.md | 4 +++- demo/run.sh | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 demo/run.sh diff --git a/README.md b/README.md index e299751..bc51a01 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,13 @@ pip install -e . ### Docker You can run a containerized demo using Docker. It will install the needed dependencies and allow you to test the FANPredictor on a sample image. -`docker build -t ibug-face_alignment -f ./demo/Dockerfile . && docker run -it --rm ibug-face_alignment` +Either run `bash demo/run.sh` or `docker build -t ibug-face_alignment -f ./demo/Dockerfile . && docker run -it --rm ibug-face_alignment` You will automatically enter a tmux session and run demo.py script. If you don't want this, you can either kill it immediately or provide "--entrypoint /bin/bash" to the docker run command. Please install Docker using [the official instructions](https://docs.docker.com/get-docker/) +**NOTE** If you're running on Windows, running the container might fail, and you would need to replace `docker run` with `winpty docker run`. I also recommend running the commands from a Unix-shell, for example Git Bash, or Docker Quickstart Terminal. This is taken care of if you use the shell script. + ## How to Use ```python # Import the libraries diff --git a/demo/run.sh b/demo/run.sh new file mode 100644 index 0000000..2f17684 --- /dev/null +++ b/demo/run.sh @@ -0,0 +1,16 @@ +if ! [ "$(basename $PWD)" = "face_alignment" ] +then + echo "Please run from the base directory of this repo." + exit 1 +fi + +docker build -t ibug-face_alignment -f ./demo/Dockerfile . + +prefix="" +if [ $(uname | grep -iE "(mingw|cygwin)") ] +then + prefix="winpty" +fi + +echo $prefix +$prefix docker run -it --rm ibug-face_alignment From 1f05150b3b3c3fa8d84e2f91776a2dbea4c9ed0b Mon Sep 17 00:00:00 2001 From: Leonardo Aoun Date: Sat, 3 Dec 2022 20:05:06 +0000 Subject: [PATCH 3/4] [docker] test on windows and add instructions --- README.md | 4 +++- demo/run.sh | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 demo/run.sh diff --git a/README.md b/README.md index e299751..bc51a01 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,13 @@ pip install -e . ### Docker You can run a containerized demo using Docker. It will install the needed dependencies and allow you to test the FANPredictor on a sample image. -`docker build -t ibug-face_alignment -f ./demo/Dockerfile . && docker run -it --rm ibug-face_alignment` +Either run `bash demo/run.sh` or `docker build -t ibug-face_alignment -f ./demo/Dockerfile . && docker run -it --rm ibug-face_alignment` You will automatically enter a tmux session and run demo.py script. If you don't want this, you can either kill it immediately or provide "--entrypoint /bin/bash" to the docker run command. Please install Docker using [the official instructions](https://docs.docker.com/get-docker/) +**NOTE** If you're running on Windows, running the container might fail, and you would need to replace `docker run` with `winpty docker run`. I also recommend running the commands from a Unix-shell, for example Git Bash, or Docker Quickstart Terminal. This is taken care of if you use the shell script. + ## How to Use ```python # Import the libraries diff --git a/demo/run.sh b/demo/run.sh new file mode 100644 index 0000000..2f17684 --- /dev/null +++ b/demo/run.sh @@ -0,0 +1,16 @@ +if ! [ "$(basename $PWD)" = "face_alignment" ] +then + echo "Please run from the base directory of this repo." + exit 1 +fi + +docker build -t ibug-face_alignment -f ./demo/Dockerfile . + +prefix="" +if [ $(uname | grep -iE "(mingw|cygwin)") ] +then + prefix="winpty" +fi + +echo $prefix +$prefix docker run -it --rm ibug-face_alignment From 2eb3d2c6b23b46df0a4ccb5c3e0297e6e443a7bc Mon Sep 17 00:00:00 2001 From: Leonardo Aoun Date: Sat, 3 Dec 2022 20:06:49 +0000 Subject: [PATCH 4/4] [docker] Add Jupyter demo --- README.md | 4 +- demo/Dockerfile | 10 ++- demo/notebook.ipynb | 145 ++++++++++++++++++++++++++++++++++++++++++++ demo/run.sh | 2 +- 4 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 demo/notebook.ipynb diff --git a/README.md b/README.md index bc51a01..ac392e1 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,8 @@ pip install -e . ### Docker You can run a containerized demo using Docker. It will install the needed dependencies and allow you to test the FANPredictor on a sample image. -Either run `bash demo/run.sh` or `docker build -t ibug-face_alignment -f ./demo/Dockerfile . && docker run -it --rm ibug-face_alignment` -You will automatically enter a tmux session and run demo.py script. If you don't want this, you can either kill it immediately or provide "--entrypoint /bin/bash" to the docker run command. +Either run `bash demo/run.sh` or `docker build -t ibug-face_alignment -f ./demo/Dockerfile . && docker run -it --rm -p 8888:8888 ibug-face_alignment` +You will automatically enter a tmux session and open jupter-lab, you can then open the notebook.ipynb. If you don't want this, you can either kill it immediately or provide "--entrypoint /bin/bash" to the docker run command. Please install Docker using [the official instructions](https://docs.docker.com/get-docker/) diff --git a/demo/Dockerfile b/demo/Dockerfile index d186f1e..480b1d9 100644 --- a/demo/Dockerfile +++ b/demo/Dockerfile @@ -19,4 +19,12 @@ RUN pip install -e . COPY demo/main.py . -CMD ["tmux", "new-session", "/bin/bash", ";", "new-window", "python -i main.py"] +RUN conda install jupyterlab matplotlib ipywidgets + +COPY demo/notebook.ipynb . + +CMD [ \ + "tmux", \ + "new-session", "/bin/bash", ";", \ + "new-window", "jupyter-lab --ip=0.0.0.0 --no-browser --allow-root" \ +] diff --git a/demo/notebook.ipynb b/demo/notebook.ipynb new file mode 100644 index 0000000..b6ad2e5 --- /dev/null +++ b/demo/notebook.ipynb @@ -0,0 +1,145 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "b3e3e628-e16a-474e-ad32-3edb91a82ba1", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import time\n", + "import io\n", + "from typing import Callable\n", + "from contextlib import contextmanager\n", + "\n", + "import cv2\n", + "import torch\n", + "from skimage.data import astronaut\n", + "import numpy as np\n", + "from matplotlib import pyplot as plt\n", + "from PIL import Image\n", + "import ipywidgets as widgets\n", + "\n", + "from ibug.face_alignment import FANPredictor\n", + "from ibug.face_alignment.utils import plot_landmarks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eea2256f-2d81-406f-8d30-6753b026e8a4", + "metadata": {}, + "outputs": [], + "source": [ + "def detect(image):\n", + " gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n", + " face_cascade = cv2.CascadeClassifier(os.path.join(cv2.data.haarcascades, \"haarcascade_frontalface_default.xml\"))\n", + " detections = face_cascade.detectMultiScale(gray)\n", + " assert len(detections) == 1, \"Please submit an image with exactly one clear frontal face\"\n", + " x, y, w, h = detections[0]\n", + " return np.array([x, y, x+w, y+h])\n", + "\n", + "def resize(image: np.ndarray, longer_side: int) -> np.ndarray:\n", + " width, height = image.shape[:2]\n", + " largest = max(width, height)\n", + " ratio = longer_side / largest\n", + " return cv2.resize(image, (int(height * ratio), int(width * ratio)))\n", + "\n", + "@contextmanager\n", + "def time_tracking(callback: Callable[[float], None]):\n", + " start = time.perf_counter()\n", + " try:\n", + " yield\n", + " finally:\n", + " end = time.perf_counter()\n", + " callback(end - start)\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f065b832-3d29-473a-aa56-de236f5040e1", + "metadata": {}, + "outputs": [], + "source": [ + "file_upload = widgets.FileUpload()\n", + "\n", + "display(file_upload)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d18fc123-fcce-40a2-83be-0bf7fd430e99", + "metadata": {}, + "outputs": [], + "source": [ + "image = astronaut()\n", + "\n", + "for filename, file_info in file_upload.value.items():\n", + " image = np.array(Image.open(io.BytesIO(file_info['content'])))\n", + " \n", + "image = resize(image, 400)\n", + "Image.fromarray(image)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c15e1d3-2dd5-400d-85f6-46f7a1d88af5", + "metadata": {}, + "outputs": [], + "source": [ + "with time_tracking(print):\n", + " detection = detect(image)\n", + "print(f\"Detected face at {detection=}\")\n", + "\n", + "config = FANPredictor.create_config(gamma = 1.0, radius = 0.1, use_jit = False)\n", + "\n", + "device = \"cpu\"\n", + "if torch.cuda.is_available():\n", + " device = torch.cuda.current_device()\n", + "\n", + "fan = FANPredictor(device=device, model=FANPredictor.get_model('2dfan2_alt'), config=config)\n", + "with time_tracking(print):\n", + " landmarks, scores = fan(image, detection)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "afef425a-84d1-4ee2-b14b-8ee8bbbd21f6", + "metadata": {}, + "outputs": [], + "source": [ + "vis = image.copy()\n", + "plot_landmarks(vis, landmarks[0])\n", + "\n", + "Image.fromarray(vis)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/demo/run.sh b/demo/run.sh index 2f17684..8f6ceaa 100644 --- a/demo/run.sh +++ b/demo/run.sh @@ -13,4 +13,4 @@ then fi echo $prefix -$prefix docker run -it --rm ibug-face_alignment +$prefix docker run -it --rm -p 8888:8888 ibug-face_alignment