{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "2c2df050-8d87-467a-bac4-db82196f9476", "metadata": {}, "outputs": [], "source": [ "import cv2\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "from math import atan2\n", "from os import listdir, path\n", "from PIL import Image as PImage" ] }, { "cell_type": "code", "execution_count": null, "id": "66f93746-7ea0-4856-ac86-24472166cf8c", "metadata": {}, "outputs": [], "source": [ "img_filename = \"MT.png\"\n", "\n", "pimg = PImage.open(f\"./{img_filename}\").convert(\"L\")\n", "pimg.thumbnail((1000,1000))\n", "imgg = np.array(pimg).copy()\n", "\n", "iw,ih = pimg.size" ] }, { "cell_type": "code", "execution_count": null, "id": "86c17ae6-391b-474f-a157-71af179f29a0", "metadata": {}, "outputs": [], "source": [ "# https://medium.com/analytics-vidhya/facial-landmarks-and-face-detection-in-python-with-opencv-73979391f30e\n", "# https://www.researchgate.net/figure/The-68-specific-human-face-landmarks_fig4_331769278\n", "\n", "haarcascade = \"./models/haarcascade_frontalface_alt2.xml\"\n", "face_detector = cv2.CascadeClassifier(haarcascade)\n", "\n", "LBFmodel = \"./models/lbfmodel.yaml\"\n", "landmark_detector = cv2.face.createFacemarkLBF()\n", "landmark_detector.loadModel(LBFmodel)\n", "\n", "faces = face_detector.detectMultiScale(imgg)\n", "\n", "biggest_faces = faces[np.argsort(-faces[:,2])]\n", "\n", "_, landmarks = landmark_detector.fit(imgg, biggest_faces)" ] }, { "cell_type": "code", "execution_count": null, "id": "7724f3dd-ee63-48a3-8761-a0ae065c480f", "metadata": {}, "outputs": [], "source": [ "OUT_W = 130\n", "OUT_H = 170\n", "OUT_EYE_SPACE = 60\n", "OUT_NOSE_TOP = 70\n", "\n", "EYE_0_IDX = 36\n", "EYE_1_IDX = 45\n", "CHIN_IDX = 8\n", "\n", "for landmark in landmarks:\n", " eye0 = np.array(landmark[0][EYE_0_IDX])\n", " eye1 = np.array(landmark[0][EYE_1_IDX])\n", " chin = np.array(landmark[0][CHIN_IDX])\n", " mid = np.mean([eye0, eye1], axis=0)\n", "\n", " eye_line = eye1 - eye0\n", " tilt = atan2(eye_line[1], eye_line[0])\n", " tilt_deg = 180 * tilt / np.pi\n", " print(tilt_deg)\n", "\n", " chin_line = chin - mid\n", " tilt2 = atan2(chin_line[1], chin_line[0])\n", " tilt2_deg = (180 * tilt2 / np.pi) - 90\n", " print(tilt2_deg)\n", "\n", " scale = OUT_EYE_SPACE / abs(eye0[0] - eye1[0])\n", "\n", " # scale\n", " pimgs = pimg.resize((int(iw * scale), int(ih * scale)), resample=PImage.Resampling.LANCZOS)\n", "\n", " # rotate around nose\n", " new_mid = [int(c * scale) for c in mid]\n", " crop_box = (new_mid[0] - (OUT_W // 2),\n", " new_mid[1] - OUT_NOSE_TOP,\n", " new_mid[0] + (OUT_W // 2),\n", " new_mid[1] + (OUT_H - OUT_NOSE_TOP))\n", "\n", " pimgsrc0 = pimgs.rotate(0, center=new_mid, resample=PImage.Resampling.BICUBIC).crop(crop_box)\n", " display(pimgsrc0)\n", " pimgsrc = pimgs.rotate(tilt_deg, center=new_mid, resample=PImage.Resampling.BICUBIC).crop(crop_box)\n", " display(pimgsrc)\n", " pimgsrc2 = pimgs.rotate(tilt_deg, center=new_mid, resample=PImage.Resampling.BICUBIC).crop(crop_box)\n", " display(pimgsrc2)\n" ] } ], "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.10.9" } }, "nbformat": 4, "nbformat_minor": 5 }