s444380-wko/wko-08.ipynb

682 lines
1.0 MiB
Plaintext
Raw Permalink Normal View History

2023-01-22 20:08:13 +01:00
{
"cells": [
{
"cell_type": "markdown",
"id": "909d3c02",
"metadata": {},
"source": [
"![Logo 1](img/aitech-logotyp-1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Widzenie komputerowe </h1>\n",
"<h2> 08. <i>Rozpoznawanie twarzy</i> [laboratoria]</h2> \n",
"<h3>Andrzej Wójtowicz (2021)</h3>\n",
"</div>\n",
"\n",
"![Logo 2](img/aitech-logotyp-2.jpg)"
]
},
{
"cell_type": "markdown",
"id": "7a9fde6b",
"metadata": {},
"source": [
"W poniższych materiałach zaprezentujemy klasyczne metody rozpoznawania twarzy. Opisywane zagadnienia można odnaleźć w *5.2.3 Principal component analysis* R. Szeliski (2022) *Computer Vision: Algorithms and Applications* oraz [dokumentacji](https://docs.opencv.org/4.5.3/da/d60/tutorial_face_main.html).\n",
"\n",
"Na początku załadujmy niezbędne biblioteki."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "1d86977a",
"metadata": {},
"outputs": [],
"source": [
"import cv2 as cv\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"import sklearn.metrics\n",
"import ipywidgets\n",
"import os\n",
"import random"
]
},
{
"cell_type": "markdown",
"id": "c5a62135",
"metadata": {},
"source": [
"Rozpakujmy zbiór danych, na którym będziemy pracować:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "0e0f1723",
"metadata": {},
"outputs": [],
"source": [
"!cd datasets && unzip -qo yaleextb.zip"
]
},
{
"cell_type": "markdown",
"id": "e6a0efb1",
"metadata": {},
"source": [
"Nasz zbiór zawiera po kilkadziesiąt zdjęć kilkudziesięciu osób, które zostały sfotografowane w różnych warunkach oświetlenia. Wczytane zdjęcia podzielimy na zbiór treningowy i testowy w stosunku 3/1 oraz wyświetlimy kilka przykładowych zdjęć:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "7b775bbf",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAxIAAAGxCAYAAAD204CiAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9a4x02VUejj+nurvul76997nZ8WAbCCbYxCGQnxTiiICCgrCUQFCEEApSFCMFK4piKYEgRbIURQoiIeJLAklERJIPQQiQJTAEK4ntgAlEgG2MPbZnxvPeu+t+6e6q/4f3/+x6avXa+5x6552ZrnEvqdVVp87ZZ5999l7redZea+9ssVgscCmXcimXcimXcimXcimXcimXsoaU3ugKXMqlXMqlXMqlXMqlXMqlXMrmySWRuJRLuZRLuZRLuZRLuZRLuZS15ZJIXMqlXMqlXMqlXMqlXMqlXMrackkkLuVSLuVSLuVSLuVSLuVSLmVtuSQSl3Ipl3Ipl3Ipl3Ipl3Ipl7K2XBKJS7mUS7mUS7mUS7mUS7mUS1lbLonEpVzKpVzKpVzKpVzKpVzKpawtl0TiUi7lUi7lUi7lUi7lUi7lUtaWSyJxKZdyKZdyKZdyKZdyKZdyKWvLJZG4lEu5lEu5lEu5lEu5lEu5lLXlDSUSP/MzP4PnnnsO1WoV733ve/F//s//eSOrcymX8rrKZf+/lK9muez/l/LVLpdj4FLeDPKGEYn/8l/+Cz74wQ/iJ37iJ/B7v/d7eNe73oXv+I7vwN27d9+oKl3Kpbxuctn/L+WrWS77/6V8tcvlGLiUN4tki8Vi8Ubc+L3vfS+++Zu/Gf/m3/wbAMB8PsfTTz+NH/3RH8U//sf/OHntfD7HV77yFbRaLWRZ9npU91K+ymSxWKDf7+PmzZsolZ483341/Z/nX46BS3kt5bUcA5f9/1IuulxkG3DZ/y/ltZZ1+v/261SnFZnNZvjUpz6FD33oQ+FYqVTC+973Pnz84x8/d/50OsV0Og3fX375ZXzt137t61LXS/nqlhdffBFPPfXUEy1z3f4PXI6BS3nj5EmPgcv+fymbJBfBBlz2/0t5o6RI/39DiMT9+/dxdnaGa9eurRy/du0aPvOZz5w7/8Mf/jB+8id/8tzxnZ0dlyllWYbFYoEsy1y2rsdKpVJhRs9y7T34nZ8XiwWKTPTo+bZeXl3n83m0rry//s46zufzc+0xn89xdnYWjmkd9Jnsc9jvtq3t/VPH2fb6fWtrC9vb2yiVSuGvXC6jVquhXq+jXq+j2WyGZ6pUKsiyDIPBAN1uF6enpyt1nc/nmM/nOD09xdnZWSivXC7j7OwM4/EYJycnOD09xenpKSaTCSaTCRaLBW7fvo1WqxV7fY8t6/Z/ID4GtrcfDeFYXwdW35ntc/a4PZbqx6m+aMdJXh1Zp9i41bGm53rPZMdmqs6pclJemFT98sao3iNWHr9zjJRKJWxvb6NcLqPT6aBaraJaraLT6WBnZweVSgUHBwfodDoYj8c4OzvD/v4+Wq0WOp0ODg4OcOXKFbzlLW9J9unT01P82q/9Gn7rt34LR0dH+O///b8/8THwJPv///f//X9ot9sAgMlkgul0isVigclkgnK5jK2tLcxmM+zs7KBaraLZbAZd0mq10Gg0UK1WMZvNMBwOcXZ2hslkgvv37+Phw4fIsgz1eh1bW1tYLBao1+vodDoreuno6AiDwSDomNlsBgAol8solUo4PT0NeqbVauHatWvY3d1FvV7HlStXwvcsy3B6eorZbIatrS2Uy2X0+31MJpOVum9tbWE+n6NUKoVz2+02Wq0Wtre3MZlMcHZ2hp2dHZycnGBnZwcAMB6PUa/Xsb29je3tbZydnaHf7+PBgwehTba3tzGdTpFlGZrNJqrVKubzOUajEYbDIebzOXZ2drCzsxPG2XA4xHA4RL/fx3Q6xdnZGU5OTnB2dobT09OVPs/2mM/n2NrawtbWVjiP7TSZTHB6ehr08tnZWSh/MBiEtmSdxuNxaHOWM5/P3X5Ee6C/W71xdnYWzh0MBhfCBsT6/4/92I9he3sbOzs7WCwWgWyUy2XX9rKt5/M5Tk5OQrtRx9Bmst0Vc8xmM2RZttJ/ptNpaMuzs7OV6xeLRbDHvC/f6Ww2C++Z11MXn52dhXfAz1ZP0/5T7PvW3xRL8Dn5rKyn3j/LMmxtba2Ux/L5m2KL1L3Vllg7qPezds+zS7Yenp0paq89+6Xl81i/3y/U/98QIrGufOhDH8IHP/jB8L3X6+Hpp58+d946BMEbZFpGzNBbcK738UC312lS9bYdyiphr172Wb3nsp3dgiQPjMU6tn0OLSsPLNoy+XlrawtZlmFnZwflcjmUS6XFZ9za2kKlUkGpVMJoNMJkMglGvdFooNvtBiClCoTlaz1qtRqq1WpQZvP5HMPhEIPBAJPJZKVd3mhJjYFYX6ZYMG9/s8dTxDYl2tc9pZVSZN4xS4C8unt9ScvyniXVTrF7ec+oYg1FXvmx37x6WH1QKpXQaDRQLpdRrVZXxkez2US9Xkev18N0OsX29jYqlQqq1SoODw/RbrfRaDSSJOn7vu/7cOPGDfzCL/xC8nleT4n1/1KpFBxKJycnoR2q1WrQJQQewBKYqINhNBrh5OQEJycnAaA3m03MZjOcnp6iUqlgZ2cnOF5KpVIIKSG5KJVKwSYQDNNZUyqVUK1Ww/3H4zHa7TaazSZ2d3dx5coVXL9+HeVyGQ8ePMDDhw8DaSSwL5fLaLVagSA0Gg3s7OwEIEedeHZ2FgB6lmXhXS8Wi1BerVYDgAAK+cyVSgWVSgW3bt0KoJ46eWtrK4BVPhcJGG3T1tZW0Lfb29srgJWAlHUhUMuyLLwjPhvJBknI6ekptre3w3ORfLDvb21tYTwe4/T0NLx/AkRvnKpYBwCvKeIYeD0l1v9p9wjs+Y70PbC/s805BtTuUQiu2fbz+TyMg3q9HnQOy+HYYd8DHmGN6XQa3geA8H6n0ykmk0nQaSybbc568hg/k5AoMFeSo+PP2gRLJJQk8J6sI8/x7qP9nM+p7ceyPHsbs436m37X/1pXWx7HUwx72vt4ZMbet4iT0cobQiQODw+xtbWFO3furBy/c+cOrl+/fu58KjgrqYaOeUSteOd5Evu9yDFVTpZcePWiYtdzLENVJptXb6/T6PX63f5miYQ933bM2PPrgLfPyoGphohGjt40GrbpdIrxeBz6A5ViuVwOyo+GhO1IzyCNULlcDl5cKlp7/ng8xhe/+MVou74aWbf/A/ExAMQVgP6eUhoxBecpFO/danmp+qXq6J3rlR8bb3lEyV5rlXVRRRwrN6ag7RjzzvGex9ZLPWAEX+zXBFPAo/FULpeDl55AjsZ4NpuhXq+796VsbW3hPe95Dz772c/i537u55LnPo48yf6v3lgAKx5wDyCcnp4Gry098sBqm1M3tNttdLtdTCYTbG1tBQBFJwNBDoEtwTrvTY8ry+U7IkiiI4MOjFKphFqthlqtFnQRdRadJpxlOT09RbvdDkRAyRHfOe+hszLUp3zmfr8fAOBsNgu6dDQaBYIyn88DMSVgnM/nOD4+DvfhbO54PA4kZjabnSMSrB+fi/dU4Mn3xfdKssa2oyedRIlC4sMytD3s2CdA9CQPCzwJeVIYSAmexRiLxXJ2JWZ/FewDS4el6hOC73K5jEqlEjzynPkiUea9eU8F4xx7Z2dnoc9yNl1nqXhP/jabzUJ9VM/a52I5+k5Zb+uMUVGiQ+zBuns4zCtLdTSvV90Tw0wWj9nz9TlStoL30rrafuDZu5gtt+UWkTeESJTLZbz73e/GRz/6UXzP93wPgEcN/9GPfhQf+MAHXlXZ6wCVGHjyzvGmQllvOxD1Ximgn2J+tiPod68OscHi1ScmFrTYe3tALPU8sfb1OrZ+piLR7zpdOhqNgnfNkg81lCcnJwF0VavVMJvRarXCND4V32w2w3Q6xc7OTpjSfq3kSfb/PFBqzy1aJrDaH7z3lEdgU+L1DS3Tel74m0csipAZ7x6x+sZIV6yOep7nIIjplFj5Xn2tRx1YkgSC3O3
"text/plain": [
"<Figure size 1200x500 with 8 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"dataset_dir = \"datasets/yaleextb\"\n",
"\n",
"img_data = []\n",
"img_labels = []\n",
"\n",
"images = os.listdir(dataset_dir)\n",
"\n",
"n_examples = 15\n",
"\n",
"for i in range(1, 40):\n",
" i_str = str(i).zfill(2)\n",
" images_p = [img for img in images if img.startswith(f\"yaleB{i_str}\")]\n",
" \n",
" for img in images_p[:n_examples]:\n",
" img_data.append(cv.imread(f\"{dataset_dir}/{img}\", cv.IMREAD_GRAYSCALE))\n",
" img_labels.append(i)\n",
"\n",
"random.seed(1337)\n",
"selector = random.choices([False, True], k=len(images), weights=[3, 1])\n",
"train_data = [x for x, y in zip(img_data, selector) if not y]\n",
"train_labels = [x for x, y in zip(img_labels, selector) if not y]\n",
"test_data = [x for x, y in zip(img_data, selector) if y]\n",
"test_labels = [x for x, y in zip(img_labels, selector) if y]\n",
"\n",
"plt.figure(figsize=(12,5))\n",
"for i in range(4):\n",
" plt.subplot(251 + i)\n",
" plt.imshow(train_data[i], cmap='gray');\n",
"for i in range(4):\n",
" plt.subplot(256 + i)\n",
" plt.imshow(train_data[-i-20], cmap='gray');"
]
},
{
"cell_type": "markdown",
"id": "6e315630",
"metadata": {},
"source": [
"Pierwszym modelem jest *Eigenfaces* zaimplementowany w [`EigenFaceRecognizer`](https://docs.opencv.org/4.5.3/dd/d7c/classcv_1_1face_1_1EigenFaceRecognizer.html). Główny pomysł polega na użyciu PCA do redukcji wymiarów. W naszym przykładzie zachowamy 60 wektorów własnych."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "0473c8ae",
"metadata": {},
"outputs": [],
"source": [
"model = cv.face.EigenFaceRecognizer_create(60)\n",
"model.train(np.array(train_data), np.array(train_labels))"
]
},
{
"cell_type": "markdown",
"id": "7a753f2d",
"metadata": {},
"source": [
"Zachowane wektory własne możemy zwizualizować:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "f797fe86",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA9oAAADnCAYAAADhGy6pAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOy9fci1a1rXf9z3/dwvz7PfBsv2ODj6syi1IAWtaUj/qCZ0CsmcP1IkxCQpGqGGiEZKG4gGIkgsI5DIgqQXCKEiwSYoiFHT6o8wQ0VK09mmtmfv/eznfl3r98fmu9bn+qzjvNb97Hn2c6/HWQcs1lrXul7O8ziPl+/3OM/rWgfL5XJZe9nLXvayl73sZS972cte9rKXvezlicjhXTdgL3vZy172spe97GUve9nLXvayl99Isifae9nLXvayl73sZS972cte9rKXvTxB2RPtvexlL3vZy172spe97GUve9nLXp6g7In2Xvayl73sZS972cte9rKXvexlL09Q9kR7L3vZy172spe97GUve9nLXvaylycoe6K9l73sZS972cte9rKXvexlL3vZyxOUPdHey172spe97GUve9nLXvayl73s5QnKnmjvZS972cte9rKXvexlL3vZy1728gRlT7T3spe97GUve9nLXvayl73sZS97eYKyJ9p72cte9rKXvexlL3vZy172spe9PEG5U6L9fd/3ffX//X//X52dndX73ve++vEf//G7bM5e9vJUZW//e/lslr397+WzXfY+sJfPZtnb/14+G+TOiPY/+2f/rD7ykY/Ud3/3d9d/+S//pb7sy76svuZrvqZ+5Vd+5a6atJe9PDXZ2/9ePptlb/97+WyXvQ/s5bNZ9va/l88WOVgul8u7uPD73ve++j2/5/fU3/27f7eqqhaLRb33ve+t7/iO76i//Jf/8uyxi8WifumXfqleeOGFOjg4eBrN3cteVrJcLuv111+v97znPXV4+PZqVZ+J/Wf/vQ/s5a7kM/WBvf3v5VmWu84Be/vfy13LPgfs5bNZHsf+7z2lNk3k8vKyfvInf7I++tGPrrYdHh7WBz7wgfrkJz+5sf/FxUVdXFysvv+f//N/6nf+zt/5VNq6l72M5Bd+4Rfq8z//8x/7uMe1/6q9D+xlN+Xt+MDe/vfyG0WeVg7Y2/9edlX2OWAvn81yG/u/E6L9q7/6q3Vz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
"text/plain": [
"<Figure size 1200x500 with 5 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"img_shape = train_data[0].shape\n",
"plt.figure(figsize=(12,5))\n",
"for i in range(5):\n",
" e_v = model.getEigenVectors()[:,i]\n",
" e_v = np.reshape(e_v, img_shape)\n",
"\n",
" plt.subplot(151+i)\n",
" plt.imshow(e_v, cmap='gray');"
]
},
{
"cell_type": "markdown",
"id": "19545151",
"metadata": {},
"source": [
"Możemy zobaczyć jakie potencjalne twarze znajdują się w naszej przestrzeni. Do *uśrednionej* twarzy dodajemy kolejne wektory własne z odpowiednimi wagami. Poniżej mamy przykład wykorzystujący 6 wektorów:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "5265f337",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "21cd4f92037e40549d3f9fa336b038b2",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(IntSlider(value=0, description='w_0', max=128, min=-128), IntSlider(value=0, description…"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mean = model.getMean()\n",
"W = model.getEigenVectors()\n",
"\n",
"def generate_face(**args):\n",
" img = mean.copy()\n",
" for i, k in enumerate(args.keys()):\n",
" img = np.add(img, W[:,i]*(10*args[k]))\n",
" \n",
" img = np.reshape(img, img_shape)\n",
" plt.figure(figsize=(5,5))\n",
" plt.imshow(img, cmap='gray')\n",
" plt.show()\n",
" \n",
"ipywidgets.interactive(generate_face, \n",
" w_0=ipywidgets.IntSlider(min=-128, max=128),\n",
" w_1=ipywidgets.IntSlider(min=-128, max=128),\n",
" w_2=ipywidgets.IntSlider(min=-128, max=128),\n",
" w_3=ipywidgets.IntSlider(min=-128, max=128),\n",
" w_4=ipywidgets.IntSlider(min=-128, max=128),\n",
" w_5=ipywidgets.IntSlider(min=-128, max=128))"
]
},
{
"cell_type": "markdown",
"id": "fd4bdce6",
"metadata": {},
"source": [
"Możemy teraz spróbować zrobić rekonstrukcję np. pierwszej twarzy ze zbioru treningowego. Pobieramy dla niej projekcje (wagi) z naszego modelu i podobnie jak wyżej wykorzystujemy uśrednioną twarz i wektory własne. Możemy zobaczyć, że użycie większej liczby wektorów powoduje zwiększenie precyzji rekonstrukcji:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "2619c6f9",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1200x600 with 7 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pro = model.getProjections()[0]\n",
"\n",
"def reconstruct_face(k):\n",
" img = mean.copy()\n",
"\n",
" for i in range(k):\n",
" img = np.add(img, W[:,i]*pro[0,i])\n",
" \n",
" return img\n",
"\n",
"plt.figure(figsize=(12,6))\n",
"for i in range(6):\n",
" k = (i+1)*10\n",
" r_face = np.reshape(reconstruct_face(k), img_shape)\n",
" j = 0 if i <= 4 else 10\n",
" plt.subplot(151+i+100)\n",
" plt.imshow(r_face, cmap='gray')\n",
" plt.title(f\"k = {k}\")\n",
" \n",
"plt.subplot(257)\n",
"plt.imshow(train_data[0], cmap='gray');\n",
"plt.title(\"original\");"
]
},
{
"cell_type": "markdown",
"id": "ae87277a",
"metadata": {},
"source": [
"Spróbujmy teraz odnaleźć osobny znajdujące się na dwóch przykładowych obrazach ze zbioru testowego. Dla nieznanej twarzy obliczamy projekcje i szukamy metodą najbliższego sąsiada projekcji ze zbioru treningowego. Poniżej mamy przykład z poprawnym rozpoznaniem osoby oraz z niepoprawnym rozpoznaniem:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "828f3134",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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cllhZnsg50VuvPHGdkSkf+12uz0/P991zwc+8IF2RLR/93d/t7r2Mz/zM+2IaL/rXe/qSr++vt5ut9vt3/u932sPDQ213/e+93X8/qY3vakdEe2///u/b1zvX/7lX25HRPu2225Lf7/++utrf5e8+93vbkdE+5d+6Zeqa6urq+0nPOEJ7Yho33jjjdX1Jz3pSe0nPelJaVmHDx+u/n/f+97Xjoj22972to50f/7nf951/fDhw+2IaP/5n/95R9rjx4+3JyYm2j/xEz/Rcf2Hf/iH29PT0+25ubnadnldV1dX20tLSx1pjh071t6/f3/7BS94QXXttttua0dEe3Jysv2FL3yhuv5P//RP7Yhov/zlL6+uPfWpT20/6lGPai8uLlbX1tfX21/7tV/b/pIv+ZLq2nvf+952RLTf+9731tZZ6Zr89RpXyr333tuOiParX/3qxve88IUvbA8PD7c//elPN75nIAPJ5HLH2POBKY9+9KPb3/RN31Rb7kte8pKqj5vIADM3ZICZ9TKIkJ5neeMb3xgPfehDu65zL+PKykqcPHkyHvKQh8SOHTviwx/+cDz3uc+NiIg/+qM/ikc/+tGph6elkj/8wz+Mhz/84fGwhz2sI1LwlKc8JSIi3vve98bXfu3XnpP2vOUtb+lYbi/Je97znhgZGYkf+qEfqq4NDw/Hy172snjf+963qbL/8A//MGZnZ+NpT3taRzuvvfba2LZtW7z3ve+N5zznOdX1q6++umsJfnZ2Nr71W781/vf//t9xww03RKvVirW1tfiDP/iDeNaznhXT09N91Wl4eDiGh4cj4sx2guPHj8f6+no85jGPiQ9/+MNd6Z/1rGfFlVdeWf3/2Mc+Nh73uMfFe97znvi1X/u1uO++++Kv//qv47WvfW2cOnUqTp06VaW97rrr4tWvfnXccccdHXn0kkc/+tHVklsvOXDgQON8+5W3v/3t8eY3vzle+cpXxpd8yZect3IGcnnJ5YqxknOJKTt27Ih/+7d/i1tuueW8zdEBZjaXyw0zB4T0PMtjH/vYdMP9wsJC3HDDDXHjjTfGHXfcEe12u/qNSwW33nprPPvZz64t45ZbbolPfvKTxc3S99xzzyZrv3n57Gc/G1dccUVs27at4/o111yz6TxvueWWOHHiROzbty/93dvpT95Kvu/7vi/+4A/+IN73vvfFE5/4xLjpppvi7rvvrgxUv/I7v/M78au/+qtd+76y8jNQeehDHxrveMc7IiLiM5/5TLTb7fjpn/7p+Omf/um0vHvuuacvcN25c2d8/dd/feP050Pe9773xQtf+MK47rrr4ud//ucval0GcmnJ5YqxknOJKa997WvjW7/1W+OhD31oPPKRj4xv+IZviOc+97nxZV/2Zee0zgPM7C2XI2YOCOlFkpe97GVx4403xo/8yI/E13zN18Ts7Gy0Wq347u/+7lhfX+8rr/X19XjUox4Vv/Zrv5b+fujQoXNR5fMmrVarw1hI1tbWOv5fX1+Pffv2xdve9rY0HzcWpSfqr7vuuti/f3+89a1vjSc+8Ynx1re+NQ4cOLApAHrrW98az3ve8+JZz3pW/PiP/3js27cvhoeH44Ybbohbb7217/w09j/2Yz9WfMDqIQ95SF95Li8vx3333dco7d69e6voxbmSj370o/HMZz4
"text/plain": [
"<Figure size 800x1100 with 4 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def find_face(query_id):\n",
" query_face = test_data[query_id]\n",
" query_label = test_labels[query_id]\n",
"\n",
" x = np.reshape(query_face, mean.shape)\n",
" x_coeff = np.dot(x - mean, W)\n",
"\n",
" best_face = None\n",
" best_label = None\n",
" best_dist = float('inf')\n",
"\n",
" for i, p in enumerate(model.getProjections()):\n",
" dist = np.linalg.norm(np.reshape(p, 60) - np.reshape(x_coeff, 60))\n",
"\n",
" if dist < best_dist:\n",
" best_face = train_data[i]\n",
" best_label = train_labels[i]\n",
" best_dist = dist\n",
" \n",
" return query_face, query_label, best_face, best_label\n",
"\n",
"qf_1, ql_1, bf_1, bl_1 = find_face(45)\n",
"qf_2, ql_2, bf_2, bl_2 = find_face(10)\n",
"\n",
"plt.figure(figsize=(8,11))\n",
"plt.subplot(221)\n",
"plt.imshow(qf_1, cmap='gray')\n",
"plt.title(f\"Face 1: query label = {ql_1}\")\n",
"plt.subplot(222)\n",
"plt.imshow(bf_1, cmap='gray');\n",
"plt.title(f\"Face 1: best label = {bl_1}\")\n",
"plt.subplot(223)\n",
"plt.imshow(qf_2, cmap='gray')\n",
"plt.title(f\"Face 2: query label = {ql_2}\")\n",
"plt.subplot(224)\n",
"plt.imshow(bf_2, cmap='gray');\n",
"plt.title(f\"Face 2: best label = {bl_2}\");"
]
},
{
"cell_type": "markdown",
"id": "43f9a8e5",
"metadata": {},
"source": [
"Bardziej kompaktowe wykonanie predykcji możemy uzyskać poprzez metodę `predict()`:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "bf736bdd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"12 12\n",
"2 16\n"
]
}
],
"source": [
"print(test_labels[45], model.predict(test_data[45])[0])\n",
"print(test_labels[10], model.predict(test_data[10])[0])"
]
},
{
"cell_type": "markdown",
"id": "eeaf62b5",
"metadata": {},
"source": [
"Jak widać poniżej, metoda ta nie uzyskuje szczególnie zadowalających wyników (generalnie słabo sobie radzi w sytuacji zmian oświetlenia):"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "12c65438",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy: 31.25 %\n"
]
}
],
"source": [
"predictions = []\n",
"for test_img in test_data:\n",
" p_label, p_conf = model.predict(test_img)\n",
" predictions.append(p_label)\n",
" \n",
"print(f\"Accuracy: {sklearn.metrics.accuracy_score(test_labels, predictions) * 100:.2f} %\")"
]
},
{
"cell_type": "markdown",
"id": "ea5d879b",
"metadata": {},
"source": [
"Poniżej krótko zaprezentujemy jeszcze dwa rozwinięcia tego algorytmu. Pierwszym z nich jest *Fisherfaces* zaimplementowany w [`FisherFaceRecognizer`](https://docs.opencv.org/4.5.3/d2/de9/classcv_1_1face_1_1FisherFaceRecognizer.html). Tym razem przy pomocy LDA chcemy dodatkowo uwzględnić rozrzut pomiędzy klasami (por. [przykład](https://sthalles.github.io/fisher-linear-discriminant/)). Poniżej tworzymy model z 40 komponentami:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "4eb5b746",
"metadata": {},
"outputs": [],
"source": [
"model = cv.face.FisherFaceRecognizer_create(40)\n",
"model.train(np.array(train_data), np.array(train_labels))"
]
},
{
"cell_type": "markdown",
"id": "e9f334be",
"metadata": {},
"source": [
"Zauważmy, że uzyskujemy tutaj ponad dwukrotnie lepszy wynik:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "96faa192",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy: 79.86 %\n"
]
}
],
"source": [
"predictions = []\n",
"for test_img in test_data:\n",
" p_label, p_conf = model.predict(test_img)\n",
" predictions.append(p_label)\n",
" \n",
"print(f\"Accuracy: {sklearn.metrics.accuracy_score(test_labels, predictions) * 100:.2f} %\")"
]
},
{
"cell_type": "markdown",
"id": "02220e5f",
"metadata": {},
"source": [
"Dalszym rozwinięciem jest model *Local Binary Patterns Histograms* (LBPH) zaimplementowany w [`LBPHFaceRecognizer`](https://docs.opencv.org/4.5.3/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html). W tym wypadku chcemy np. uwzględnić możliwość innego oświetlenia osób niż taki, który występuje w naszym zbiorze treningowym. Podobnie jak wcześniej zależy nam na redukcji wymiarów, ale tym razem uzyskamy to poprzez wyliczanie cech (progowanie) dla poszczególnych pikseli w zadanych regionach."
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "61eeffdf",
"metadata": {},
"outputs": [],
"source": [
"model = cv.face.LBPHFaceRecognizer_create(radius=10, neighbors=10, grid_x=32, grid_y=32)\n",
"model.train(np.array(train_data), np.array(train_labels))"
]
},
{
"cell_type": "markdown",
"id": "0d64cb5a",
"metadata": {},
"source": [
"Uzyskany wynik jest o kilka punktów procentowy lepszy od poprzedniego modelu, jednak możemy zauważyć, że zmiana domyślnych parametrów na takie, które zwiększają precyzję, powoduje również zwiększenie czasu potrzebnego na wykonanie predykcji:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "ca2e319d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy: 90.97 %\n"
]
}
],
"source": [
"predictions = []\n",
"for test_img in test_data:\n",
" p_label, p_conf = model.predict(test_img)\n",
" predictions.append(p_label)\n",
" \n",
"print(f\"Accuracy: {sklearn.metrics.accuracy_score(test_labels, predictions) * 100:.2f} %\")"
]
},
{
"cell_type": "markdown",
"id": "00196405",
"metadata": {},
"source": [
"# Zadanie 1\n",
"\n",
"W katalogu `datasets` znajduje się zbiór zdjęć `att_faces`. Sprawdź jakiego typu są to zdjęcia oraz jak powyższe algorytmy działają na tym zbiorze."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "51b8a256",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"400\n",
"320\n",
"80\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1200x500 with 8 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# miejsce na eksperymenty\n",
"import os\n",
"import random\n",
"import cv2 as cv\n",
"import matplotlib.pyplot as plt\n",
"dataset_dir = \"datasets/att_faces\"\n",
"\n",
"img_data = []\n",
"img_labels = []\n",
"\n",
"images = os.listdir(dataset_dir)\n",
"print(len(images))\n",
"n_examples = 15\n",
"\n",
"for i in range(1, 41):\n",
" i_str = str(i).zfill(2)\n",
" images_p = [img for img in images if img.startswith(f\"s{i_str}\")]\n",
" \n",
" for img in images_p[:n_examples]:\n",
" img_data.append(cv.imread(f\"{dataset_dir}/{img}\", cv.IMREAD_GRAYSCALE))\n",
" img_labels.append(i)\n",
"\n",
"random.seed(1300)\n",
"selector = random.choices([False, True], k=len(images), weights=[3, 1])\n",
"new_selector = [False for _ in range(400)]\n",
"\n",
"for x in range(40):\n",
" first_random, second_random = random.sample(range(10), 2)\n",
" while first_random == second_random:\n",
" second_random = random.sample(range(10), 1)\n",
" \n",
" new_selector[x*10 + first_random] = True\n",
" new_selector[x*10 + second_random] = True\n",
"\n",
"selector = new_selector\n",
"\n",
"train_data = [x for x, y in zip(img_data, selector) if not y]\n",
"train_labels = [x for x, y in zip(img_labels, selector) if not y]\n",
"\n",
"test_data = [x for x, y in zip(img_data, selector) if y]\n",
"test_labels = [x for x, y in zip(img_labels, selector) if y]\n",
"\n",
"print(len(train_data))\n",
"print(len(test_data))\n",
"\n",
"plt.figure(figsize=(12,5))\n",
"for i in range(4):\n",
" plt.subplot(251 + i)\n",
" plt.imshow(train_data[i], cmap='gray');\n",
"for i in range(4):\n",
" plt.subplot(256 + i)\n",
" plt.imshow(train_data[-i], cmap='gray');"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "932734b5-ae4e-4ebf-957b-fff41e36fa02",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy: 95.00 %\n",
"Accuracy: 96.25 %\n",
"Accuracy: 92.50 %\n"
]
}
],
"source": [
"import numpy as np\n",
"import sklearn.metrics\n",
"\n",
"model = cv.face.EigenFaceRecognizer_create(60)\n",
"model.train(np.array(train_data), np.array(train_labels))\n",
"\n",
"predictions = []\n",
"for test_img in test_data:\n",
" p_label, p_conf = model.predict(test_img)\n",
" predictions.append(p_label)\n",
" \n",
"print(f\"Accuracy: {sklearn.metrics.accuracy_score(test_labels, predictions) * 100:.2f} %\")\n",
"model = cv.face.FisherFaceRecognizer_create(100)\n",
"model.train(np.array(train_data), np.array(train_labels))\n",
"\n",
"predictions = []\n",
"for test_img in test_data:\n",
" p_label, p_conf = model.predict(test_img)\n",
" predictions.append(p_label)\n",
" \n",
"print(f\"Accuracy: {sklearn.metrics.accuracy_score(test_labels, predictions) * 100:.2f} %\")\n",
"\n",
"model = cv.face.LBPHFaceRecognizer_create(radius=10, neighbors=8, grid_x=8, grid_y=8)\n",
"model.train(np.array(train_data), np.array(train_labels))\n",
"\n",
"predictions = []\n",
"for test_img in test_data:\n",
" p_label, p_conf = model.predict(test_img)\n",
" predictions.append(p_label)\n",
" \n",
"print(f\"Accuracy: {sklearn.metrics.accuracy_score(test_labels, predictions) * 100:.2f} %\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6c52502e-0969-4411-8cb0-4307858c1b9e",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"author": "Andrzej Wójtowicz",
"email": "andre@amu.edu.pl",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"lang": "pl",
"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.2"
},
"subtitle": "08. Rozpoznawanie twarzy [laboratoria]",
"title": "Widzenie komputerowe",
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}