wko/wko-08_att_faces.ipynb

557 lines
779 KiB
Plaintext
Raw Normal View History

2023-01-16 09:35:16 +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": 4,
"id": "0e0f1723",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"'unzip' is not recognized as an internal or external command,\n",
"operable program or batch file.\n"
]
}
],
"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": 8,
"id": "7b775bbf",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1200x500 with 8 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"dataset_dir = \"datasets/att_faces\"\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, 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(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": 9,
"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": 10,
"id": "f797fe86",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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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": 11,
"id": "5265f337",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "a2b7f20bef1c44d8a9445716d00940d9",
"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": 11,
"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": 12,
"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": 13,
"id": "828f3134",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAqQAAANnCAYAAADnTUoHAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9ebxWVd3/j7/POYxOICog8yAKKqKCKM5TN9mgltVtmaGWWjmkfsr0/jrlXVHdlWZ6a4MfrdRKTc3Kj95mzhIOqIkDoAIKCGqKgAPDOfv3h79r38+9uF6X+9jBi3PO6/l4+HgsrrOHtdZea+3ter2HhizLsjDGGGOMMaZONNa7AsYYY4wxpnPjD1JjjDHGGFNX/EFqjDHGGGPqij9IjTHGGGNMXfEHqTHGGGOMqSv+IDXGGGOMMXXFH6TGGGOMMaau+IPUGGOMMcbUFX+QGmOMMcaYuuIPUmNawb777hv77rtvq8+bN29eNDQ0xA9/+MM2q8tdd90VDQ0Ncdddd7XZNY0x7YN1saasC7xmmrL4g3QdceWVV0ZDQ0PV/84444x6V6/ArFmz4tRTT43dd989evToEQ0NDTFv3rx6V8usp3znO9+Jgw8+OPr16xcNDQ1x3nnnyWP/+te/xn777Rebb7559O7dOyZOnBi/+c1vPrjKmg6L19j6cMstt9Sc82ZtvGaWo0u9K9DROf/882P48OGF37bffvs61aY606ZNi4suuii23XbbGDNmTDz22GP1rpJZjznrrLOif//+sdNOO8Vtt90mj7v55pvj0EMPjUmTJsV5550XDQ0Nce2118YXvvCFePXVV+PUU0/9AGttOipeYz9Ybrnllrjkkkv8UdoKvGaWwx+k65iDDjooJkyYUO9q1OTggw+OpUuXxsYbbxw//OEP2/ViqciyLN55553o2bNnvavS7pk7d24MGzYsXn311dhiiy3kcRdffHFsueWW8be//S26d+8eERHHH398jB49Oq688soOv7iaDwavsWZ9x2tmOSzZ14n58+fHV7/61dhmm22iZ8+esdlmm8WnP/3pqjLO0qVL49RTT41hw4ZF9+7dY9CgQfn/MVVYuXJlnHvuubHVVltF9+7dY/DgwXH66afHypUr37Muffr0iY033rhUvV966aV45plnYvXq1e957NKlS+Ooo46KXr16Re/evWPKlCnx2GOPRUNDQ1x55ZX5ccrG6Kijjophw4YVfmtpaYkLL7wwtttuu+jRo0f069cvjj/++Hj99dcLxw0bNiw+9rGPxW233RYTJkyInj17xs9+9rPYZ599Yty4cVXru80228TkyZPfs11k1apVcc4558T48eOjV69eseGGG8Zee+0Vd955pzznggsuiKFDh0bPnj1jn332iZkzZ651zDPPPBOf+tSnok+fPtGjR4+YMGFC3Hzzza2q27oifSaKZcuWxaabbpovrBERXbp0ic0339z/Y2DWOZ1hja3QVmvK6tWr41vf+laMGjUqevToEZtttlnsueeecfvtt0fEu2vyJZdcEhFRMJFoDV4zNZ19zfQO6TrmjTfeKCxqERGbb755PPTQQ/HAAw/E4YcfHoMGDYp58+bFpZdeGvvuu2889dRTscEGG0RExIoVK2KvvfaKp59+Oo455pjYeeed49VXX42bb745FixYEJtvvnm0tLTEwQcfHPfdd18cd9xxMWbMmHjiiSfiggsuiNmzZ8dNN93UZu0588wz41e/+lX+f3yKLMvikEMOifvuuy++/OUvx5gxY+LGG2+MKVOm/Ev3P/744+PKK6+Mo48+Ok4++eSYO3duXHzxxfHoo4/G/fffH127ds2PnTVrVnz2s5+N448/Po499tjYZpttYqONNopjjz02Zs6cWZD1HnrooZg9e3acddZZrarPsmXL4pe//GV89rOfjWOPPTaWL18el19+eUyePDkefPDB2HHHHQvH//rXv47ly5fHCSecEO+880785Cc/if333z+eeOKJ6NevX0REPPnkk7HHHnvEwIED44wzzogNN9wwrr322jj00EPjD3/4Q3ziE59oVR1Xr14db7zxRqlj+/TpE42NbfP/qfvuu298//vfj7PPPjumTJkSDQ0Ncc0118TDDz8c1157bZvcw5jOusZWaMs15bzzzoupU6fGl770pZg4cWIsW7YsHn744ZgxY0Z86EMfiuOPPz4WLVoUt99++/u2a/Saqen0a2Zm1glXXHFFFhFV/8uyLHvrrbfWOmfatGlZRGS//vWv89/OOeecLCKyG264Ya3jW1pasizLst/85jdZY2Njdu+99xb+ftlll2URkd1///2l6/1f//VfWURkc+fOrfr3KVOm1Px7hZtuuimLiOwHP/hB/tuaNWuyvfbaK4uI7Iorrsh/32effbJ99tmn6r2GDh2a//vee+/NIiK7+uqrC8fdeuuta/0+dOjQLCKyW2+9tXDs0qVLsx49emTf/OY3C7+ffPLJ2YYbbpitWLGiZrvSuq5ZsyZbuXJl4ZjXX38969evX3bMMcfkv82dOzeLiKxnz57ZggUL8t+nT5+eRUR26qmn5r8dcMAB2dixY7N33nkn/62lpSXbfffds1GjRuW/3XnnnVlEZHfeeWfNOleOK/Pfez1X8sorr2QRkZ177rlV/75ixYrsM5/5TNbQ0JBff4MNNshuuumm0vcwRtHZ19h1saaMGzcu++hHP1rzvieccELex2Xwmvm/eM2sjXdI1zGXXHJJbL311mv9zu331atXx7Jly2KrrbaK3r17x4wZM+LII4+MiIg//OEPMW7cuKr/h1eRSq677roYM2ZMjB49urBTsP/++0dExJ133hm77757m7TnyiuvLMjtiltuuSW6dOkSX/nKV/Lfmpqa4qSTTop77733fd37uuuui169esWHPvShQjvHjx8fG220Udx5553xuc99Lv99+PDha0nwvXr1ikMOOSR++9vfxtSpU6OhoSGam5vj97//fRx66KGx4YYbtqpOTU1N0dTUFBHvmhMsXbo0WlpaYsKECTFjxoy1jj/00ENj4MCB+b8nTpwYu+66a9xyyy3x4x//OF577bX429/+Fueff34sX748li9fnh87efLkOPfcc2PhwoWFa7wX48aNyyW396J///6lr/tedO/ePbbeeuv41Kc+FZ/85Cejubk5fv7zn8fnP//5uP3222O33XZrs3uZzktnXWMrtOWa0rt373jyySdjzpw5MWrUqDZpT4rXTE1nXzP9QbqOmThxYlWD+7fffjumTp0aV1xxRSxcuDCyLMv/Rqngueeei8MOO6zmPebMmRNPP/20NJZ++eWX32ft3z/z58+PLbfcMjbaaKPC79tss837vuacOXPijTfeiL59+1b9e9rO1PO2whe+8IX4/e9/H/fee2/svffe8de//jWWLFmSv6Bay69+9av40Y9+tJbdV7X7V1vkt95661yOefbZZyPLsjj77LPj7LPPrnq/l19+uVWL66abbhoHHnhg6ePbihNPPDH+/ve/x4wZM3JJ6zOf+Uxst9128bWvfS2mT5/+gdfJdDw66xpboS3XlPPPPz8OOeSQ2HrrrWP77bePD3/4w3HkkUfGDjvs0KZ19ppZnc6+ZvqDtE6cdNJJccUVV8Qpp5wSkyZNil69ekVDQ0Mcfvjh0dLS0qprtbS0xNixY+PHP/5x1b8PHjy4Laq8zmhoaCi8LCo0NzcX/t3S0hJ9+/aNq6++uup10peFMgKfPHly9OvXL6666qrYe++946qrror+/fu/rwXoqquuiqOOOioOPfTQ+MY3vhF9+/aNpqammDp1ajz33HOtvl7l2X/961+XDlZbbbVVq665atWqeO2110odu8UWW+S7F/8Kq1atissvvzxOP/30gn1V165d46CDDoqLL744Vq1aFd26dfuX72VMNbzGvktr1pS99947nnvuufjjH/8Y//M//xO//OUv44ILLojLLrssvvSlL7VJfbxm6nt29jXTH6R14vrrr48pU6bEj370o/y3d955J5YuXVo4buTIkVU9CtNjHn/88TjggANa7fG4rhg6dGjccccdsWL
"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": 14,
"id": "bf736bdd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"18 18\n",
"3 3\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": 15,
"id": "12c65438",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy: 98.96 %\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": 16,
"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": 17,
"id": "96faa192",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy: 97.92 %\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": 18,
"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": 19,
"id": "ca2e319d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy: 86.46 %\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."
]
}
],
"metadata": {
"author": "Andrzej Wójtowicz",
"email": "andre@amu.edu.pl",
"kernelspec": {
"display_name": "widzenie_komputerowe",
"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",
2023-01-30 13:54:58 +01:00
"version": "3.7.12 | packaged by conda-forge | (default, Oct 26 2021, 05:35:01) [MSC v.1916 64 bit (AMD64)]"
2023-01-16 09:35:16 +01:00
},
"subtitle": "08. Rozpoznawanie twarzy [laboratoria]",
"title": "Widzenie komputerowe",
"vscode": {
"interpreter": {
"hash": "6ac7fc53e11b5e853f03d2492fedb08fce658edca143f79fa3d2748d3b63b777"
}
},
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}