File size: 3,957 Bytes
4e75693 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
{
"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
}
|