widzenie-komputerowe-MP/wko-06.ipynb

920 lines
368 KiB
Plaintext
Raw Permalink Normal View History

2023-01-23 12:24:42 +01:00
{
"cells": [
{
"cell_type": "markdown",
"id": "819ce420",
"metadata": {},
"source": [
"![Logo 1](img/aitech-logotyp-1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Widzenie komputerowe </h1>\n",
"<h2> 06. <i>Rozpoznawanie i segmentacja obrazów</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": "a6dc5acc",
"metadata": {},
"source": [
"W poniższych materiałach zobaczymy w jaki sposób możemy klasycznym podejściem rozpoznawać ludzi na zdjęciach, a ponadto w jaki sposób szybko podzielić obraz na elementy znajdujące się na pierwszym planie i w tle obrazu.\n",
"\n",
"Na początku załadujmy niezbędne biblioteki."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "e45bb312",
"metadata": {},
"outputs": [],
"source": [
"import cv2 as cv\n",
"import numpy as np\n",
"import sklearn.svm\n",
"import sklearn.metrics\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"import os\n",
"import random"
]
},
{
"cell_type": "markdown",
"id": "5b757675",
"metadata": {},
"source": [
"Naszym głównym celem będzie rozpoznawanie ludzi na zdjęciach przy pomocy klasycznej metody *histogram of oriented gradients* (HOG). Krótko mówiąc, dla danego zdjęcia chcemy uzyskać wektor cech, który będziemy mogli wykorzystać w klasyfikatorze SVM. Szczegóły znajdują się w *6.3.2 Pedestrian detection* R. Szeliski (2022) *Computer Vision: Algorithms and Applications*, natomiast tutaj zobrazujemy techniczne wykorzystanie tej metody.\n",
"\n",
"# Klasyfikacja obrazów przy użyciu HOG i SVM\n",
"\n",
"Spróbjemy zbudować klasyfikator, który wskazuje czy na zdjęciu znajduje się osoba z okularami czy bez okularów. Rozpakujmy zbiór danych, z którego będziemy korzystali:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "7b953b82",
"metadata": {},
"outputs": [],
"source": [
"!cd datasets && unzip -qo glasses.zip"
]
},
{
"cell_type": "markdown",
"id": "f4a457f3",
"metadata": {},
"source": [
"Następnie wczytujemy dane i dzielimy je na dwa zbiory w proporcjach 80/20:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "737d95c1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Train data: 1272, test data: 319\n"
]
}
],
"source": [
"dataset_dir = \"datasets/glasses\"\n",
"images_0 = os.listdir(f\"{dataset_dir}/with\")\n",
"images_0 = [f\"{dataset_dir}/with/{x}\" for x in images_0]\n",
"images_1 = os.listdir(f\"{dataset_dir}/without\")\n",
"images_1 = [f\"{dataset_dir}/without/{x}\" for x in images_1]\n",
"images = images_0 + images_1\n",
"random.seed(1337)\n",
"random.shuffle(images)\n",
"\n",
"train_data = []\n",
"test_data = []\n",
"train_labels = []\n",
"test_labels = []\n",
"\n",
"splitval = int((1-0.2)*len(images))\n",
"\n",
"for x in images[:splitval]:\n",
" train_data.append(cv.imread(x, cv.IMREAD_COLOR))\n",
" train_labels.append(x.split(\"/\")[2])\n",
" \n",
"for x in images[splitval:]:\n",
" test_data.append(cv.imread(x, cv.IMREAD_COLOR))\n",
" test_labels.append(x.split(\"/\")[2])\n",
" \n",
"d_labels = {\"with\": 0, \"without\": 1}\n",
" \n",
"train_labels = np.array([d_labels[x] for x in train_labels])\n",
"test_labels = np.array([d_labels[x] for x in test_labels])\n",
"\n",
"print(f\"Train data: {len(train_data)}, test data: {len(test_data)}\")"
]
},
{
"cell_type": "markdown",
"id": "265147e3",
"metadata": {},
"source": [
"Poniżej znajduje się kilka przykładowych zdjęć."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "e0595915",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAlAAAABCCAYAAACYY+j8AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAACWx0lEQVR4nOz915Ola3beif1e97ntd/rKMqfq+DanfTccAQ5IDjEDRpATIYkzEzEKKSTNlaTQjUL6J3RBja5G0kRImosJXWgGZNAN4QECRAONNqf7nFPHlK/KSrczt/vsa3Tx7io0IHYDjS41pY5aEVWZuU3uL7/1mvWu9aznESEEXtpLe2kv7aW9tJf20l7aX93kv+sLeGkv7aW9tJf20l7aS/v/N3sZQL20l/bSXtpLe2kv7aX9iPYygHppL+2lvbSX9tJe2kv7Ee1lAPXSXtpLe2kv7aW9tJf2I9rLAOqlvbSX9tJe2kt7aS/tR7SXAdRLe2kv7aW9tJf20l7aj2g/VgAlhPgVIcRtIcTHQoj//Yu6qJf278Ze+vOnx1768qfLXvrzp8de+vKnx8RflwdKCKGAD4G/AzwC/hj4T0II7724y3tpPyl76c+fHnvpy58ue+nPnx576cufLvtxMlBfBT4OIdwJIbTAfwP8/RdzWS/t34G99OdPj7305U+XvfTnT4+99OVPkekf472HwMPv+/kR8LW/+CIhxH8O/OcAAvGl6XRKkecIAc47EmMoy5K2bXHe4/0mIxYCSim0Ugji90IIlJIYrVFSIgAhAiF4pBCbt3mEEIjnnw+E+DWE+FoCIEBs3sOzLNzmcb4vKRc2PzzP1IUQHw1/9jYfAj7EVwoh8T7QWYv38TG/eWHY/CeljO/x/tk9ih+7eY4Q4nuD/3P3MkkStFLgA1IKpBD4EK9RShn/Pv/sswLOe+rOUrcdLoB1Fu+94N9uf6k//7wv+ZIUEq2jf6QUJEaTJglaSQQBrWS8Eh+QStFZixAK7zydtbDxybosydKMrusIBLIsQwpJlud0XYuSkuA9tmvJsowszXDexxFFwBiFsxYApTVKKUIA21m01kgV3x+8e+7zZy4Wm0EiACElQkb/ee8RG19IIaMfvQPAOUcIASFF/CpEvJLN94SAkJKu6zZjJY45710cpwG893jv47UR8MGjlH4+qIIP+OfjUNA0LS4EhFSUTUPbdTQ2nIUQdv46vvyL/lRCfGlrkKOEQGuF3MwPZTRSKrSK91EI8D7g4lj6vrkiEDLeByklQgq00vGePrvnAqRU8fsQxyzPZupfGJUC8WdzUfzZk3/1fPn3TdDNLwrPHw7PPy54jw+e4D3OWZx1OOeif5zH++jr537ZzE2Ic1WI+DXLM9I0BQLWWghgbQfP14U4PuI48jjvsdbhXMA5x6JuqTv3Yuam4EuJhOloQJElKCmf//3eh+fjU0nFuixp6gbnPXmesy7XICRKKbx1aK1J02Tje0nXts/XYu89JkkQQiCVJknM5jn5/K4L8Wfr3/N7/ucvPF7P/6f3CH7zuPyzZ5+t7CH82bB4tmw/+xtDCEgh4veAFHLzGYLwbFA988dmzvoQ56MQAr8Z21rJuM4TCN7FdcE5vN+Mj+AJIeBCwPnAcl3Rth6TpFRN88LmpoAvZYkiNRop4jobvN+sc3HvezamlZJIIZBCIlWcX8/mbNyTNvvjZr/wIaCkfO7TzWejlYp7jIy+lFLw5+bR5nVCiD8/d8OzxwSIP8vPPHtZvOffPwo2P3/ffvjsd4fNOhzXG4/zDttZOmtx3m/GgMA5t/Hhn5+jz67Pe4cQoKTEWQfBkxqD0pIkMUgpsS768/s8gPMBj+ByWVJ39t86N3+cAOqvZCGE/xL4LwF6RS/8w7//H/G1r36Za4dXsK7ju9/9Lp/97Gf5P/6j/4L5coV1cQFK05SurRkPB9TlmvFoQC9PSBTcODzg+sEevVSRaghdjVZQpAnBd2gdgyspBQKPazuUkigZJwA+gIjPhxAXMAL4zpIm6XOHBLEJjAJY57DWYq2naRxl3dJZj/XghMQKwaIsma8qlmXFYl2xrhpWTYMPgjTNcdajhaZ1llVVYoMHrTDGkBmDsAGFZFT0WVzOcdailaHpWkyaMCwKxoni2u4Ow15BcB1p0dssjALvHKnShBAo247j5ZxPnp7y/uMnrDt4cn72wnyZGBOGRcqV3W0EFmU7Xrt1nTdvXCURgcO9KYKOXp7z6PFjiuGYxaom70/4zd/61wwGY+7cvc/29hQvPOPxmE/u3uFifsloMmJrexdrLc52DHs546LH9njA6mLG7s42Siuqcs0bt25Qr+a89tpN0iJjPN6iKPr0egOk0qzWS8bjEdI51vNL6rZGSIWUGts58jxnNBzSdR2dtQwnEzrvqeoGkyS41rJcLFkvl6RZivOW+WLO/PKC69euQoDj4xO6ECdgHDsx2F1czkhNDIqePnmMtx1JkuI6y6Do4bsaRKC0NSbVFL2ctm5QAQiCunHUnadzinVteXx+ydmq5LSsef+TT7h31t5/Uf7cHfXCP/z5z3Aw7jPoZUgs0kgODg4oegP2t/ZI05ynT59w+/ZtFosFSkoynaGlQScGaTRZlmOMobYdQggGgz57+/tsbW+T5zlSKdIi3wRZGqEVSmsCHilFXMiVBCHjZickIUYp8ecAz1ZsAYhnhxgcLtgYzHvA+83zm0OG8zgbA5e2rqjWK1bLORfnpywuL1jM5zR1x3K5ot0ECa7tcM5RFAXDwYBBv09RFBS9Ht47ZrMLynLNer2ibip2dqbcunWT8WDI6dkxdV3RthXIGGw77/EBrIeq7jg7u+TicsXsfM7//Q/e/3Fc+ed8WSQ6vDrW/C/+R3+XV69soYUlSSXzdUmS5mid0O8N+F//r/4P/L1/73WUzuisRRvNzpU9qqYmL/rMTi5Yr9dcXJ4zmUw4PjlnOr1Kv8iZL2Zs7+7Qth2rVYP3gq2tKTs7W3z6jTcZ9Htsj8dIJUiylCxLnh8uAYQU+M1GK5Eo5PNN0BFgE4xvTrrPA6rgAs5aJAKldayhOEvXNrRdzWK5YDQYUiQFKklYdC0ffvQhDz+5x+HeAW3bcLlc4CXc/vBDBv0+/aLH9u4Of/L1P+Znv/o1Hj16wG/+5m+ipODNT73NL/3SLyIl4C3L+QLhA21XoRLNbDmj8XC+avnDP3mP926fMBxO+ejk6IXNzUGRhU9dGzPKFZ99/RUSHAZHkWQx8LcW1zX08oIsy9iaTOicIy+GXC5X3P7oE5xQLBYrbPCUVQNa4b1gVa4RSrK7s8N0MqWpalarBTeuXaOpana2t9jd3WJnZ8qwX5CqgJbQL1K0FvHwGjwmTZHa4AIIZVBKx/ktFZK4N0kpMUbjfEcIHtc1tHWFxNNVFc5arHV4L3BOsFiWnJ5d0HaB+WXJvQePWazXZL0+FsFgPOHOvQecnJ1gvWWxXjHs9Ul0Si8vSNMM4QP37t6mn3t2t7ZITY70gXI+ZzQscL7l05/9DDJLKKuKYLtNYBqobaAVCf+n/+73f6CffpwA6jFw7ft+vrp57AdaYjRVtaYsV3zzm9/k8ZNH9POC/+v/+f/CztYW5+cXuOARSJxtca7j9PwU23Ws6zV4S5ElLJdzFstLQlVy/XCPfmboZYZqtaJXZNSVQylIEoOWAhccInhc0+Gd3UTwghiMxpOHEiBFwNo2ZsecxwVw3tO0HdYFhDQ0naCsA+sqsFjXrJqWxnu81CyqivP5Ao9gtS5ZrEo6FwMwrRzOWhKtCQKE1rS2w9YtoW4xUpFpg7CeclmCF2RJwnJdYozh8nJJuVhQKsHOsMegyMnzHOs8UiuM1nTfd6JSSpGnGUWek2tF5/7Ss/uP5M8QPHkvZ7leoYVnmCak2tDUDcNJn7btGA0Lqq6jP55yuSz5wz/5FiYbcLEuefDkjMFkzEf3H7K7t8PdR++R93p8+gtfoWlbVmXF6dk5u9vbzMuW+aJiVTXU6xVPZ0uqeoWRnocP75Ebxcf37jIajxFCYDvPF770FT7/hc8jtGK1WiGdw4dAkmQEIekPRqRJhtSacr1mNps
"text/plain": [
"<Figure size 720x144 with 5 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.figure(figsize=(10,2))\n",
"for i in range(5):\n",
" plt.subplot(151 + i)\n",
" plt.imshow(train_data[i][:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "e05e27e8",
"metadata": {},
"source": [
"Tworzymy deskryptor HOG przy pomocy funkcji [`cv.HOGDescriptor()`](https://docs.opencv.org/4.5.3/d5/d33/structcv_1_1HOGDescriptor.html). Metodą [`compute()`](https://docs.opencv.org/4.5.3/d5/d33/structcv_1_1HOGDescriptor.html#a38cd712cd5a6d9ed0344731fcd121e8b) tworzymy wektory cech, które posłużą nam jako dane wejściowe do klasyfikatora. Poniżej znajduje się również przykładowa konfiguracja deskryptora:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "f21e8924",
"metadata": {},
"outputs": [],
"source": [
"hp_win_size = (96, 32)\n",
"hp_block_size = (8, 8)\n",
"hp_block_stride = (8, 8)\n",
"hp_cell_size = (4, 4)\n",
"hp_n_bins = 9\n",
"hp_deriv_aperture = 0\n",
"hp_win_sigma = 4.0\n",
"hp_histogram_norm_type = 1\n",
"hp_l2_hys_threshold = 0.2\n",
"hp_gamma_correction = True\n",
"hp_n_levels = 64\n",
"hp_signed_gradient = True\n",
"\n",
"hog_descriptor = cv.HOGDescriptor(\n",
" hp_win_size, hp_block_size, hp_block_stride, hp_cell_size, \n",
" hp_n_bins, hp_deriv_aperture, hp_win_sigma, \n",
" hp_histogram_norm_type, hp_l2_hys_threshold, \n",
" hp_gamma_correction, hp_n_levels, hp_signed_gradient)\n",
"\n",
"train_hog = np.vstack([hog_descriptor.compute(x).ravel() for x in train_data])\n",
"test_hog = np.vstack([hog_descriptor.compute(x).ravel() for x in test_data])"
]
},
{
"cell_type": "markdown",
"id": "755b8ebe",
"metadata": {},
"source": [
"Do klasyfikacji użyjemy klasyfikatora SVM. Możemy użyć implementacji znajdującej się w module [`cv.ml`](https://docs.opencv.org/4.5.3/d1/d2d/classcv_1_1ml_1_1SVM.html):"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "b46783d4",
"metadata": {},
"outputs": [],
"source": [
"model = cv.ml.SVM_create()\n",
"model.setGamma(0.02)\n",
"model.setC(2.5)\n",
"model.setKernel(cv.ml.SVM_RBF)\n",
"model.setType(cv.ml.SVM_C_SVC)"
]
},
{
"cell_type": "markdown",
"id": "d8f47c54",
"metadata": {},
"source": [
"Trenujemy model:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "810f9a1e",
"metadata": {},
"outputs": [],
"source": [
"model.train(np.array(train_hog), cv.ml.ROW_SAMPLE, train_labels);"
]
},
{
"cell_type": "markdown",
"id": "69d39eee",
"metadata": {},
"source": [
"Sprawdzamy wynik na danych testowych:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "763b6dc7",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ACC: 95.61 %\n"
]
}
],
"source": [
"predictions = model.predict(test_hog)[1].ravel()\n",
"accuracy = (test_labels == predictions).mean()\n",
"print(f\"ACC: {accuracy * 100:.2f} %\")"
]
},
{
"cell_type": "markdown",
"id": "2dd04ec5",
"metadata": {},
"source": [
"Możemy również użyć implementacji klasyfikatora znajdującej się w bibliotece [`scikit-learn`](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html):"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "13b7ba1c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ACC: 95.61 %\n"
]
}
],
"source": [
"model = sklearn.svm.SVC(C=2.5, gamma=0.02, kernel='rbf')\n",
"model.fit(train_hog, train_labels)\n",
"\n",
"predictions = model.predict(test_hog)\n",
"accuracy = (test_labels == predictions).mean()\n",
"print(f\"ACC: {accuracy * 100:.2f} %\")"
]
},
{
"cell_type": "markdown",
"id": "2259c310",
"metadata": {},
"source": [
"# Rozpoznawanie ludzi\n",
"\n",
"Powyższą metodykę klasyfikcji możemy zastosować do rozpoznawania obiektów na zdjęciach, np. ludzi. W tym wypadku będziemy chcieli wskazać gdzie na zdjęciu znajduje się dany obiekt lub obiekty.\n",
"\n",
"Rozpocznijmy od rozpakowania zbioru danych:"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "d8497390",
"metadata": {},
"outputs": [],
"source": [
"!cd datasets && unzip -qo inria-person-sub.zip"
]
},
{
"cell_type": "markdown",
"id": "30374bad",
"metadata": {},
"source": [
"Wczytujemy dane, które są już podzielone na dwa zbiory:"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "978d77cf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Train data: 1457, test data: 560\n"
]
}
],
"source": [
"dataset_dir = \"datasets/INRIAPerson\"\n",
"\n",
"images_train_0 = os.listdir(f\"{dataset_dir}/train_64x128_H96/negPatches\")\n",
"images_train_0 = [f\"{dataset_dir}/train_64x128_H96/negPatches/{x}\" for x in images_train_0]\n",
"images_train_1 = os.listdir(f\"{dataset_dir}/train_64x128_H96/posPatches\")\n",
"images_train_1 = [f\"{dataset_dir}/train_64x128_H96/posPatches/{x}\" for x in images_train_1]\n",
"\n",
"images_test_0 = os.listdir(f\"{dataset_dir}/test_64x128_H96/negPatches\")\n",
"images_test_0 = [f\"{dataset_dir}/test_64x128_H96/negPatches/{x}\" for x in images_test_0]\n",
"images_test_1 = os.listdir(f\"{dataset_dir}/test_64x128_H96/posPatches\")\n",
"images_test_1 = [f\"{dataset_dir}/test_64x128_H96/posPatches/{x}\" for x in images_test_1]\n",
"\n",
"train_data = []\n",
"test_data = []\n",
"train_labels = []\n",
"test_labels = []\n",
"\n",
"for x in images_train_0:\n",
" img = cv.imread(x, cv.IMREAD_COLOR)\n",
" if img is not None:\n",
" train_data.append(img)\n",
" train_labels.append(0)\n",
"\n",
"for x in images_train_1:\n",
" img = cv.imread(x, cv.IMREAD_COLOR)\n",
" if img is not None:\n",
" train_data.append(img)\n",
" train_labels.append(1)\n",
" \n",
"for x in images_test_0:\n",
" img = cv.imread(x, cv.IMREAD_COLOR)\n",
" if img is not None:\n",
" test_data.append(img)\n",
" test_labels.append(0)\n",
"\n",
"for x in images_test_1:\n",
" img = cv.imread(x, cv.IMREAD_COLOR)\n",
" if img is not None:\n",
" test_data.append(img)\n",
" test_labels.append(1)\n",
"\n",
"print(f\"Train data: {len(train_data)}, test data: {len(test_data)}\")"
]
},
{
"cell_type": "markdown",
"id": "9bf41d6e",
"metadata": {},
"source": [
"Poniżej znajduje się kilka przykładowych zdjęć ze zbioru:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "f29d47c1",
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,2))\n",
"for i in range(3):\n",
" plt.subplot(161 + i)\n",
" plt.imshow(train_data[i][:,:,::-1]);\n",
"for i in range(3):\n",
" plt.subplot(164 + i)\n",
" plt.imshow(train_data[-(i+1)][:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "57cec468",
"metadata": {},
"source": [
"Tworzymy deskryptor i wektory cech:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d5248df2",
"metadata": {},
"outputs": [],
"source": [
"hp_win_size = (64, 128)\n",
"hp_block_size = (16, 16)\n",
"hp_block_stride = (8, 8)\n",
"hp_cell_size = (8, 8)\n",
"hp_n_bins = 9\n",
"hp_deriv_aperture = 1\n",
"hp_win_sigma = -1\n",
"hp_histogram_norm_type = 0\n",
"hp_l2_hys_threshold = 0.2\n",
"hp_gamma_correction = True\n",
"hp_n_levels = 64\n",
"hp_signed_gradient = False\n",
"\n",
"hog_descriptor = cv.HOGDescriptor(\n",
" hp_win_size, hp_block_size, hp_block_stride, hp_cell_size, \n",
" hp_n_bins, hp_deriv_aperture, hp_win_sigma, \n",
" hp_histogram_norm_type, hp_l2_hys_threshold, \n",
" hp_gamma_correction, hp_n_levels, hp_signed_gradient)\n",
"\n",
"train_hog = np.vstack([hog_descriptor.compute(x).ravel() for x in train_data])\n",
"test_hog = np.vstack([hog_descriptor.compute(x).ravel() for x in test_data])"
]
},
{
"cell_type": "markdown",
"id": "c6782aa9",
"metadata": {},
"source": [
"Następnie tworzymy klasyfikator:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8f6108ed",
"metadata": {},
"outputs": [],
"source": [
"model = cv.ml.SVM_create()\n",
"model.setGamma(0)\n",
"model.setC(0.01)\n",
"model.setKernel(cv.ml.SVM_LINEAR)\n",
"model.setType(cv.ml.SVM_C_SVC)\n",
"model.setTermCriteria((cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 1000, 1e-3))"
]
},
{
"cell_type": "markdown",
"id": "bbfbde58",
"metadata": {},
"source": [
"Uczymy model:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "afd0bbb4",
"metadata": {},
"outputs": [],
"source": [
"model.train(np.array(train_hog), cv.ml.ROW_SAMPLE, np.array(train_labels));"
]
},
{
"cell_type": "markdown",
"id": "09626eed",
"metadata": {},
"source": [
"Sprawdzamy jakość klasyfikacji:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fa3be6b6",
"metadata": {},
"outputs": [],
"source": [
"predictions = model.predict(test_hog)[1].ravel()\n",
"accuracy = (test_labels == predictions).mean()\n",
"print(f\"ACC: {accuracy * 100:.2f} %\")"
]
},
{
"cell_type": "markdown",
"id": "c6df6682",
"metadata": {},
"source": [
"Poniżej znajduje się podejście przy pomocy biblioteki *scikit-learn*:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7b3de8d1",
"metadata": {},
"outputs": [],
"source": [
"model2 = sklearn.svm.SVC(C=0.01, gamma='auto', kernel='linear', max_iter=1000)\n",
"model2.fit(train_hog, train_labels)\n",
"\n",
"predictions = model2.predict(test_hog)\n",
"accuracy = (test_labels == predictions).mean()\n",
"print(f\"Accuracy: {sklearn.metrics.accuracy_score(test_labels, predictions) * 100:.2f} %\")\n",
"print(f\"Precision: {sklearn.metrics.precision_score(test_labels, predictions) * 100:.2f} %\")\n",
"print(f\"Recall: {sklearn.metrics.recall_score(test_labels, predictions) * 100:.2f} %\")"
]
},
{
"cell_type": "markdown",
"id": "6e84c568",
"metadata": {},
"source": [
"Mając teraz wyuczony model, chcielibyśmy sprawdzić czy np. na zdjęciu `img/pedestrians.jpg` znajdują się ludzie, tak aby uzyskać ew. obramowania z ich występowaniem. W pierwszej kolejności w naszym deskryptorze HOG ustawiamy współczynniki klasfikatora SVM przy pomocy metody [`setSVMDetector()`](https://docs.opencv.org/4.5.3/d5/d33/structcv_1_1HOGDescriptor.html#a6de5ac55631eed51e36278cde3a2c159). Następnie przy pomocy metody [`detectMultiScale()`](https://docs.opencv.org/4.5.3/d5/d33/structcv_1_1HOGDescriptor.html#a91e56a2c317392e50fbaa2f5dc78d30b) znajdujemy wyszukiwane obiekty (ludzi) w różnych skalach."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d6458103",
"metadata": {},
"outputs": [],
"source": [
"image = cv.imread(\"img/pedestrians.jpg\", cv.IMREAD_COLOR)\n",
"scale = 600 / image.shape[0]\n",
"image = cv.resize(image, None, fx=scale, fy=scale)\n",
"\n",
"support_vectors = model.getSupportVectors()\n",
"rho, _, _ = model.getDecisionFunction(0)\n",
"detector = np.zeros(support_vectors.shape[1] + 1, dtype=support_vectors.dtype)\n",
"detector[:-1] = -support_vectors[:]\n",
"detector[-1] = rho\n",
"\n",
"hog_descriptor.setSVMDetector(detector)\n",
"\n",
"locations, weights = hog_descriptor.detectMultiScale(\n",
" image, winStride=(8, 8), padding=(32, 32), scale=1.05,\n",
" finalThreshold=2, hitThreshold=1.0)\n",
"\n",
"for location, weight in zip(locations, weights):\n",
" x1, y1, w, h = location\n",
" x2, y2 = x1 + w, y1 + h\n",
" cv.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), thickness=3, lineType=cv.LINE_AA)\n",
" cv.putText(image, f\"{weight[0]:.2f}\", (x1,y1), cv.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2, cv.LINE_AA)\n",
"\n",
"plt.figure(figsize=(6,6))\n",
"plt.imshow(image[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "cd287c92",
"metadata": {},
"source": [
"Coś nam nawet udało się wykryć jak na tak niewielki zbiór danych uczących ;) Z drugiej strony, dwie osoby na pierwszym planie zostały pominięte, a osoba po prawej jest dyskusyjna jeśli chodzi o zakres oznaczenia.\n",
"\n",
"W OpenCV dostępny jest domyślny klasyfikator w funkcji [`HOGDescriptor_getDefaultPeopleDetector()`](https://docs.opencv.org/4.5.3/d5/d33/structcv_1_1HOGDescriptor.html#a9c7a0b2aa72cf39b4b32b3eddea78203) i poniżej możemy zobaczyć jak sobie radzi na badanym zdjęciu:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "57a745c9",
"metadata": {},
"outputs": [],
"source": [
"image = cv.imread(\"img/pedestrians.jpg\", cv.IMREAD_COLOR)\n",
"scale = 600 / image.shape[0]\n",
"image = cv.resize(image, None, fx=scale, fy=scale)\n",
"\n",
"hog_dflt_descriptor = cv.HOGDescriptor(\n",
" hp_win_size, hp_block_size, hp_block_stride, hp_cell_size, \n",
" hp_n_bins, hp_deriv_aperture, hp_win_sigma, \n",
" hp_histogram_norm_type, hp_l2_hys_threshold, \n",
" hp_gamma_correction, hp_n_levels, hp_signed_gradient)\n",
"\n",
"detector_dflt = cv.HOGDescriptor_getDefaultPeopleDetector()\n",
"hog_dflt_descriptor.setSVMDetector(detector_dflt)\n",
"\n",
"locations, weights = hog_dflt_descriptor.detectMultiScale(\n",
" image, winStride=(8, 8), padding=(32, 32), scale=1.05,\n",
" finalThreshold=2, hitThreshold=1.0)\n",
"\n",
"for location, weight in zip(locations, weights):\n",
" x1, y1, w, h = location\n",
" x2, y2 = x1 + w, y1 + h\n",
" cv.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), thickness=3, lineType=cv.LINE_AA)\n",
" cv.putText(image, f\"{weight[0]:.2f}\", (x1,y1), cv.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2, cv.LINE_AA)\n",
"\n",
"plt.figure(figsize=(6,6))\n",
"plt.imshow(image[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "6c8cf915",
"metadata": {},
"source": [
"# Segmentacja obrazu metodą GrabCut\n",
"\n",
"## Zadanie 1\n",
"\n",
"W poniższym zadaniu użyjemy algorytmu [GrabCut](https://en.wikipedia.org/wiki/GrabCut), będącego interaktywną metodą segmentacji obrazu, dzielącą obraz na pierwszy i drugi plan. W OpenCV algorytm jest zaimplementowany w funkcji [`cv.grabCut()`](https://docs.opencv.org/4.5.3/d3/d47/group__imgproc__segmentation.html#ga909c1dda50efcbeaa3ce126be862b37f). Dodatkowe informacje o algorytmie znajdują się w [dokumentacji](https://docs.opencv.org/4.5.3/d8/d83/tutorial_py_grabcut.html).\n",
"\n",
"Przygotuj interaktywną aplikację, która wykorzystuje algorytm GrabCut. W aplikacji powinna być możliwość zaznaczenia początkowego prostokąta, a następnie elementy maski (zwróć uwagę z jakich elementów może składać się maska). Przykładowe działanie możesz zaprezentować na obrazie `img/messi5.jpg`."
]
},
{
"cell_type": "markdown",
"id": "35f22bca",
"metadata": {},
"source": [
"![GrabCut - wynik](img/grabcut-result.png)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "eab14df6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" Instructions : \n",
"\n",
" Draw a rectangle around the object using right mouse button \n",
"\n",
" Now press the key 'n' a few times until no further change \n",
"\n",
" mark background regions with left mouse button \n",
"\n",
" mark foreground regions with left mouse button \n",
"\n",
" For finer touchups, mark foreground and background after pressing keys 0-3\n",
" and again press 'n' \n",
"\n",
" Result saved as image \n",
"\n",
" Result saved as image \n",
"\n",
" Result saved as image \n",
"\n",
" Result saved as image \n",
"\n",
" Result saved as image \n",
"\n",
" For finer touchups, mark foreground and background after pressing keys 0-3\n",
" and again press 'n' \n",
"\n"
]
},
{
"ename": "NameError",
"evalue": "name 'bgdmodel8' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m/tmp/ipykernel_11190/3066306653.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 151\u001b[0m \u001b[0mbgdmodel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m65\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfloat64\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[0mfgdmodel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m65\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfloat64\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 153\u001b[0;31m \u001b[0mcv2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgrabCut\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mimg2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mmask\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mrect\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mbgdmodel8\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mfgdmodel\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mcv2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mGC_INIT_WITH_MASK\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 154\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 155\u001b[0m \u001b[0mmask2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwhere\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmask\u001b[0m\u001b[0;34m==\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mmask\u001b[0m\u001b[0;34m==\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m255\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'uint8'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mNameError\u001b[0m: name 'bgdmodel8' is not defined"
]
}
],
"source": [
"import numpy as np\n",
"import cv2\n",
"import sys\n",
"'''\n",
"===============================================================================\n",
"Interactive Image Segmentation using GrabCut algorithm.\n",
"\n",
"This application shows interactive image segmentation using grabcut algorithm.\n",
"\n",
"USAGE :\n",
" python grabcut.py <filename>\n",
"\n",
"README FIRST:\n",
" Two windows will show up, one for input and one for output.\n",
"\n",
" At first, in input window, draw a rectangle around the object using\n",
"mouse right button. Then press 'n' to segment the object (once or a few times)\n",
"For any finer touch-ups, you can press any of the keys below and draw lines on\n",
"the areas you want. Then again press 'n' for updating the output.\n",
"\n",
"Key '0' - To select areas of sure background\n",
"Key '1' - To select areas of sure foreground\n",
"Key '2' - To select areas of probable background\n",
"Key '3' - To select areas of probable foreground\n",
"\n",
"Key 'n' - To update the segmentation\n",
"Key 'r' - To reset the setup\n",
"Key 's' - To save the results\n",
"===============================================================================\n",
"'''\n",
"BLUE = [255,0,0] # rectangle color\n",
"RED = [0,0,255] # PR BG\n",
"GREEN = [0,255,0] # PR FG\n",
"BLACK = [0,0,0] # sure BG\n",
"WHITE = [255,255,255] # sure FG\n",
"\n",
"DRAW_BG = {'color' : BLACK, 'val' : 0}\n",
"DRAW_FG = {'color' : WHITE, 'val' : 1}\n",
"DRAW_PR_FG = {'color' : GREEN, 'val' : 3}\n",
"DRAW_PR_BG = {'color' : RED, 'val' : 2}\n",
"\n",
"# setting up flags\n",
"rect = (0,0,1,1)\n",
"drawing = False # flag for drawing curves\n",
"rectangle = False # flag for drawing rect\n",
"rect_over = False # flag to check if rect drawn\n",
"rect_or_mask = 100 # flag for selecting rect or mask mode\n",
"value = DRAW_FG # drawing initialized to FG\n",
"thickness = 3 # brush thickness\n",
"\n",
"def onmouse(event,x,y,flags,param):\n",
" global img,img2,drawing,value,mask,rectangle,rect,rect_or_mask,ix,iy,rect_over\n",
"\n",
"\n",
"\n",
"\n",
" if event == cv2.EVENT_RBUTTONDOWN:\n",
" rectangle = True\n",
" ix,iy = x,y\n",
"\n",
" elif event == cv2.EVENT_MOUSEMOVE:\n",
" if rectangle == True:\n",
" img = img2.copy()\n",
" cv2.rectangle(img,(ix,iy),(x,y),BLUE,2)\n",
" rect = (ix,iy,abs(ix-x),abs(iy-y))\n",
" rect_or_mask = 0\n",
"\n",
" elif event == cv2.EVENT_RBUTTONUP:\n",
" rectangle = False\n",
" rect_over = True\n",
" cv2.rectangle(img,(ix,iy),(x,y),BLUE,2)\n",
" rect = (ix,iy,abs(ix-x),abs(iy-y))\n",
" rect_or_mask = 0\n",
" print (\" Now press the key 'n' a few times until no further change \\n\")\n",
"\n",
"\n",
"\n",
" # draw touchup curves\n",
" if event == cv2.EVENT_LBUTTONDOWN:\n",
" drawing = True\n",
" ix,iy = x,y\n",
" elif event == cv2.EVENT_MOUSEMOVE:\n",
" if drawing == True:\n",
" cv2.circle(img,(x,y),thickness,value['color'],-1)\n",
" cv2.circle(mask,(x,y),thickness,value['val'],-1)\n",
" elif event == cv2.EVENT_LBUTTONUP:\n",
" drawing = False\n",
" cv2.circle(img,(x,y),thickness,value['color'],-1)\n",
" cv2.circle(mask,(x,y),thickness,value['val'],-1)\n",
"\n",
"\n",
"img = cv2.imread('img/messi5.jpg')\n",
"img2 = img.copy() # a copy of original image\n",
"mask = np.zeros(img.shape[:2],dtype = np.uint8) # mask initialized to PR_BG\n",
"output = np.zeros(img.shape,np.uint8) # output image to be shown\n",
"\n",
"# input and output windows\n",
"cv2.namedWindow('output')\n",
"cv2.namedWindow('input')\n",
"cv2.setMouseCallback('input', onmouse)\n",
"cv2.moveWindow('input',img.shape[1]+10,90)\n",
"\n",
"print (\" Instructions : \\n\")\n",
"print (\" Draw a rectangle around the object using right mouse button \\n\")\n",
"\n",
"while(True):\n",
"\n",
" cv2.imshow('output',output)\n",
" cv2.imshow('input',img)\n",
" k = 0xFF & cv2.waitKey(1)\n",
"\n",
" # key bindings\n",
" if k == 27: # esc to exit\n",
" break\n",
" elif k == ord('0'): # BG drawing\n",
" print (\" mark background regions with left mouse button \\n\")\n",
" value = DRAW_BG\n",
" elif k == ord('1'): # FG drawing\n",
" print (\" mark foreground regions with left mouse button \\n\")\n",
" value = DRAW_FG\n",
" elif k == ord('2'): # PR_BG drawing\n",
" value = DRAW_PR_BG\n",
" elif k == ord('3'): # PR_FG drawing\n",
" value = DRAW_PR_FG\n",
" elif k == ord('s'): # save image\n",
" bar = np.zeros((img.shape[0],5,3),np.uint8)\n",
" res = np.hstack((img2,bar,img,bar,output))\n",
" cv2.imwrite('grabcut_output.png',output)\n",
" cv2.imwrite('grabcut_output_combined.png',res)\n",
" print (\" Result saved as image \\n\")\n",
" elif k == ord('r'): # reset everything\n",
" print (\"resetting \\n\")\n",
" rect = (0,0,1,1)\n",
" drawing = False\n",
" rectangle = False\n",
" rect_or_mask = 100\n",
" rect_over = False\n",
" value = DRAW_FG\n",
" img = img2.copy()\n",
" mask = np.zeros(img.shape[:2],dtype = np.uint8) # mask initialized to PR_BG\n",
" output = np.zeros(img.shape,np.uint8) # output image to be shown\n",
" elif k == ord('n'): # segment the image\n",
" print (\"\"\" For finer touchups, mark foreground and background after pressing keys 0-3\n",
" and again press 'n' \\n\"\"\")\n",
" if (rect_or_mask == 0): # grabcut with rect\n",
" bgdmodel = np.zeros((1,65),np.float64)\n",
" fgdmodel = np.zeros((1,65),np.float64)\n",
" cv2.grabCut(img2,mask,rect,bgdmodel,fgdmodel,1,cv2.GC_INIT_WITH_RECT)\n",
" rect_or_mask = 1\n",
" elif rect_or_mask == 1: # grabcut with mask\n",
" bgdmodel = np.zeros((1,65),np.float64)\n",
" fgdmodel = np.zeros((1,65),np.float64)\n",
" cv2.grabCut(img2,mask,rect,bgdmodel8,fgdmodel,1,cv2.GC_INIT_WITH_MASK)\n",
"\n",
" mask2 = np.where((mask==1) + (mask==3),255,0).astype('uint8')\n",
" output = cv2.bitwise_and(img2,img2,mask=mask2)\n",
"\n",
"cv2.destroyAllWindows()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "04f5a6f8",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.image.AxesImage at 0x7faacca48f70>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA20AAADQCAYAAACUTon8AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAAEAAElEQVR4nOz9S6xle7bmB/3G/zHnWntHnJOZ99a9Vb5VpkqiMBjzsLBMB2QQMqJh4Z4FdGggVQvRxR13aLnvFtVAooMwHQsaFg8hISRAopCQJRvZYJVdVS5X1b1585wTEXutOf+PMWiMMefakZn34SpnVspaIxUZcWLvWHut+fjmeHzj+8TMeMYznvGMZzzjGc94xjOe8Yxn/GZG+of9Bp7xjGc84xnPeMYznvGMZzzjGX90PIu2ZzzjGc94xjOe8YxnPOMZz/gNjmfR9oxnPOMZz3jGM57xjGc84xm/wfEs2p7xjGc84xnPeMYznvGMZzzjNzieRdsznvGMZzzjGc94xjOe8Yxn/AbHs2h7xjOe8YxnPOMZz3jGM57xjN/g+JUVbSLy3xGRf0dE/l0R+Rd/VT/nGc94xjOe8YxnPOMZz3jGM/6THPKr8GkTkQz8f4F/FvgPgL8G/PfN7P/zH/sPe8YznvGMZzzjGc94xjOe8Yz/BMevatL2TwP/rpn9dTNrwP8a+Od/RT/rGc94xjOe8YxnPOMZz3jGM/4TG7+qou33gL/17r//g/i7ZzzjGc94xjOe8YxnPOMZz3jGf4Qo/7B+sIj8FeCvAKQk/5WX6xWJr6kaU5WpE1XjKwqnCIJwfLPI8a8Ezj8bGCTxr4sISYSc5Pgqaoaqnb8fPyOlTEqCpEStiWWBUqEUyEnjNcGM89/8UoKpxBfe/35+t/zSb/+TD1r8Zsfn989papgac4IOY3ShNxjdMOK9YufnNiz+7vGO/A+PT/Lz7/Ln/1tEIAkiyY/xu3PiL3X8APvqMGD27pzF35s9Dur5L37+qPirCHE+42en5Oc2+Zvyf21xfuN1/RpI8e+P96fMOVFVwJAkEK93XEf+czI5ZVLOX31OM0NVmWMwekN1YvZ4xyKQ0s+9P45rD1SVoYqq+mvFiTKz+PGCvDukRpxnLP5O4mf465/vLY6fntdnfHdK/icRLH7OV7+On/LuYvbX9s+QUyKXQk6JlNK7c+jH2VRRPa6vx8/23/3rx5/lfM34JeLHRY0Z583PIfH+4vd4fyI8ziuC4Ac+xX0OcLvfmXMiIrxcL+ffH9fG1Mmc6tfI3we+SBzZA1vkPb68u/4OjDFThDh2KSFJWJZMXYxaoWTHF0mPe8K+Ph2/PH5l+GLny5nG5xiOMbMJrcEYdn7er/DluAbevaPzG/+Id/nVf0vcqXGd/UfDl3en6f3P/RPxJf4mftZx74r49XneO1jcr35+kJ/DwOMnnM8v9dc9PktKX11bKWVyzv7ckXS+LT/mkzEGo3dU51fv+MDAfNz/746jX9/GnMqM+86OYxX4chzP85l74M8v4Et6hy+BQxy4cX6Q8+t/WnwR4R1+J3JOlJzjuD/wxbA4Fg+c/GX4oqpgCvhxOXCxpEQS/zdTDTUNXPnj8CWOzfG54pgdx8GA2+12nttnPOMZz/iPOX5qZn/ml33hV1W0/W3gL7z77z8ff3eGmf1V4K8CfPPh1f6Zf+qfJCdhzMnnbeOnP/zAz77/zJf7xpwzHjZHsleQHIl0EswSKWeQ5A8dU7IISxHWJfPNywsf1gtL8YfBPiZf9sGn28Zta+z7jqqSpHC5vnD98MrLy5U/93vf8Ht/AX7nzw1+68fGt+vGpQ5EoO+d0SdtwkiCCZjYuwdyikTR0DlRkUg2Ib3L4B+JRooH8Vl7PB62hicOyeLhmElmZJswlLkr2025f1bevld++OnC3/tbiZ/+/mBMo0+j62TXSTNlm4Np/nfT1BPlKJTNDP25hFUAUiTFRLFUK2W9UOvFk/lcz0RHddJaY4xxJgkJL1RM9avCCYw5JnJ8PR7yqvN4sp8Pz1IqORXWZeF6vfB6vfC6rnxYKpeSKckTljYn99a5tcE+lSkJkRLHGGxO2nbnfrvR+06uheWysr68sK4LtRZyThhQ1yuX6wdePnzDermSU0ENRu9s9ze+fP6B7/7wp3z54TtMx/kgLwLLUnm9XFhqpmZPThChTeW2Nz693bnfd8acDFXmmJgqKQnrWqgCOWcA+hzsW2Pf/PsVo6TMUjNrKSwlk3JCganK0ImqkHJlXVYu68JSCyXH+1dla41tb7TW2cdATbE543wJSy1cLyuvlwvffPOBn/zoWz58fOXl5ZXLciWXxOyd1hrbbed233nbG21OhkGfxhiDvt9p253RdkAppfByWfjmZeVH15XrUlAz9jHZ+6SpMcj0Ca1P2pjc9519dHrv5FwopbKUymUpZJsUBh+u/jlFhP/n//vf4Pd/+odcLyv/1f/if57Xy0oSoY3Bp/udP/j+B7774TO3bT+vO08Wk+NLyY/kUXIk2w98Kcnx5bJWvr2+8LIsLDVhCHuffN47n9427nujtYZOJefK5eWFl9dXXj688Of/wkf+kb+g/Jk/q/zWN5OP68alTjCj753eJ02FkaJR8A5fUuAFUYBa4It47yHurwfOPBJkzgrnF/AlWxTBgS86YChjN7Y35fZp8vYDfP/7C3/nbwrf/+FgaOCLTXYd7GrsOpjmTYmhiuIF/R+JL/GesiRPkFMmLwtlvVDq6vd9LudnmHPS2n4+F6JW9sZA4IvIA090DgSJ/1ZvcKmeBZTjbvLrKhfWZeXlxJeF12XhkhMlC0OVfQzubXBrnaaGSialwlHo2Jzstxv3+xtjdkqtLNeV9frAl5QEE2FZX7i8BL4sFyRl1IzROvfbF758+p6f/fQPuH35BPYoAksSLsvC62WllkTNfj2YCG1O3u6Nz7c7921nTseD2RWzSc6JdSnUaMYoRh/v8EUVw6jZcWWtmaUUJAnT8HM7J2ZCKguXd/iSU2Ya9DnZ98bWGnvr9Dm9YJqTJH69LbU6vlwv/Oibj/w48OV6eeGyXv1cj86+7Wz3nbfbzq01mipD8Wuv96/wJYlRauX1uvDtdeXb68qlZoYp+1C2NukW+DKMNpTWx4kvY4zzelvrwmXJJB1UUT5eV9ZlwVD+r/+Pv8bnt7c/KQ96xjOe8Yy/n/gbf9QXflVF218D/rKI/CW8WPvvAf+DP+qbBbislSKJrTUS9uiMxzTCQ1EVsEGKDv+RVGk8hM0sOu+GlMK6XPhwWfmwLv7QnUqbkzkHQyetN8bonryk5K8jPnnxqY6SgDQNG4rG9K9vk9aUfRo9JWY2chVSlkiWlJQyc+q7TrR3MXN+dFv9QxqIelc3Z47Ooan69OdIZiQ6iSYkNRYz0lTGrsy7ojswE8kSJVVK9imEmWIiTAw1oZiBTiwlkgliymCe046juJDoVJaSyCX5xEnEJ5O5kGsllUwpNRKqRM75LLy+OsPRGYaM2cQnLpk5vTibqviZ8/9pnHtJgiFkyahBftcBzSlRSyZnT1pqsjhehllmTC8Cxui0eUcxLx6H0veN3nYAcslkEYrAGr+KwMSQ2Zj7G70ksggzF6YqvU16a5iaH5eUGMMLdANUBG0DkUYbmZITOXt2Os2TBTVIOVNTIpmi2Y/vslQuUbSVnBCEPgfb0viSM2+3O3vvTIMxjSTGnOMY/WCRsKZcqDmz1sKlZtYlc1kXkMyYxroslNK4l0YaA437wnRSklBLppZCzplSCrmUs5BJMR2g+vVUFyO14dfv1Jh2eGfbE/jJ1nfQSRkFYVIzrPmYhAMm5FxYMlTJLCpcqiehOWVKb9xTisGJIJF0VhEWM9acuGSh5EyJTD4Bl5q5LAv5OC68T/TtxBe/9wE6eSpDvWBO2WB6s8LMp+0zGVIql6Xyell5XSspCX1O2iDwZdB6p4/mkw3NMVX2CQYxJUwGogY9pr/TaNukdWWf0HPCAl+8SfUOX4Y+ph94gyTnr1nvFtiRxO9jjcLF1OLYJzDHPRCSJrIpi4EMO/HFGshIJMuUlClFEDXM/JqfGFOMaYHX0YC
"text/plain": [
"<Figure size 1080x360 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import cv2 as cv\n",
"import matplotlib.pyplot as plt\n",
"image = cv.imread(\"grabcut_output_combined.png\", cv.IMREAD_COLOR)\n",
"plt.figure(figsize=(15,5))\n",
"plt.subplot(111)\n",
"plt.imshow(image[:,:,::-1])"
]
}
],
"metadata": {
"author": "Andrzej Wójtowicz",
"email": "andre@amu.edu.pl",
"kernelspec": {
"display_name": "Python 3.8.12 64-bit",
"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.8.12"
},
"subtitle": "06. Segmentacja i rozpoznawanie obrazów [laboratoria]",
"title": "Widzenie komputerowe",
"vscode": {
"interpreter": {
"hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
}
},
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}