s444380-wko/wko-02.ipynb

1312 lines
3.8 MiB
Plaintext
Raw Normal View History

2022-11-14 12:19:52 +01:00
{
"cells": [
{
"cell_type": "markdown",
"id": "46f39503",
"metadata": {},
"source": [
"![Logo 1](img/aitech-logotyp-1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Widzenie komputerowe </h1>\n",
"<h2> 02. <i>Operacje binarne na obrazach</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": "c8f8f691",
"metadata": {},
"source": [
"# Progowanie\n",
"\n",
"Podczas pracy z obrazami często potrzebne jest operowanie na obrazach, które przyjmują tylko dwie skrajne wartości. Po operacji tzw. progowania (ang. *thresholding*) na obrazie będziemy mieli piksele czarne o wartości 0 lub białe o wartości 255 (lub 1, w zależności od tego na jakim typie danych i w jakiej dziedzinie operujemy).\n",
"\n",
"Na początku załadujmy niezbędne biblioteki."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "0ddcac8e",
"metadata": {},
"outputs": [],
"source": [
"import cv2 as cv\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"id": "89072615",
"metadata": {},
"source": [
"Podczas tych zajęć skupimy się na ręcznym progowaniu. Jeśli dla obrazu w skali odcieni szarości chcielibyśmy w naszym kodzie uzyskać obraz binarny, to moglibyśmy hipotetycznie wybrać jedną z trzech opcji:\n",
"\n",
"1. przejść w pętli po wszystkich pikselach, sprawdzić czy wartość danego piksela jest mniejsza od wybranej wartości progowej i na tej podstawie ustawić nowy piksel jako czarny lub biały,\n",
"2. użyć biblioteki *NumPy* (i przy pomocy wektoryzacji stworzyć macierz binarną),\n",
"3. użyć biblioteki *OpenCV*.\n",
"\n",
"W tym miejscu nie będziemy co prawda robili eksperymentu, jednak co do zasady mając do wyboru gotowe zoptymalizowane biblioteki, zdecydowanie *nie* powinniśmy implementować algorytmów od podstaw (no chyba że podczas zajęć uczymy się mechaniki danych algorytmów; na produkcji raczej będziemy preferowali gotowe rozwiązania). Różnica w wydajności między naiwną ręczną implementacją a użyciem gotowej biblioteki może być, lekko licząc, kilkudziesięciokrotna.\n",
"\n",
"Wykorzystajmy na początek funkcję [`cv2.threshold()`](https://docs.opencv.org/4.5.3/d7/d1b/group__imgproc__misc.html#gae8a4a146d1ca78c626a53577199e9c57) do zwykłego progowania z progiem ustalonym na 100:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6bf564d2",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA0QAAAGgCAYAAACKU6eTAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOy9d5ykZZU9fqqqK4fOYXoSE8goSJagCILoCiJBkCC6/pQoouvXBTHnRTAsYEZRVyTooitGDCCsYQUJIuDAJGaYntDToXLoqvr90Z/z9Hlv1xBnpqeH93w+/enuqjfcJ7xV9zzn3vsEms1mEz58+PDhw4cPHz58+PDxIkRwpg3w4cOHDx8+fPjw4cOHj5mCT4h8+PDhw4cPHz58+PDxooVPiHz48OHDhw8fPnz48PGihU+IfPjw4cOHDx8+fPjw8aKFT4h8+PDhw4cPHz58+PDxooVPiHz48OHDhw8fPnz48PGihU+IfPjw4cOHDx8+fPjw8aKFT4h8+PDhw4cPHz58+PDxooVPiHz48OHDhw8fPnz48PGihU+IfOz0eOihh/D2t78dS5YsQTweRzwex6677orzzjsP995770ybt11www03IBAIYNWqVTNtig8fPnz4eB7g57j+9Pb24qijjsLtt9/uOTYQCOCjH/3ozBjqw8csRNtMG+DDx7bE1772NVx88cXYfffd8e53vxt77703AoEAHn30UfzgBz/AQQcdhCeeeAJLliyZaVN9+PDhw4ePZ8S3v/1t7LHHHmg2m1i/fj2uvfZanHDCCfif//kfnHDCCQCAP/3pT5g3b94MW+rDx+yBT4h87LT43//9X1x44YX4l3/5F/zwhz9EJBJx7x199NG46KKLcOuttyIej2/xGsViEYlEYnuY68OHDx8+fDwj9tlnHxx44IHu/+OPPx6dnZ34wQ9+4AjRoYceOiO2+d+ZPmYr/JA5HzstPv3pTyMUCuFrX/uahwwpTjvtNAwODgIA3vrWtyKVSuHvf/87jjvuOKTTaRxzzDEAgDvuuANveMMbMG/ePMRiMSxduhTnnXcehoeH3bXuvvtuBAIB/OAHP5h2n+9+97sIBAL461//CgBYsWIFzjjjDAwODiIajaK/vx/HHHMMHnjgAc95N954I17+8pcjlUohlUphv/32w/XXX+/efzZ2PR1+85vf4JhjjkEmk0EikcDhhx+O3/72t8/qXB8+fPjwMfOIxWKIRCIIh8PuNRsyx3C73//+97jgggvQ09OD7u5unHzyyVi3bp3nejfffDOOO+44zJkzB/F4HHvuuScuu+wyFAoFz3Fb+s78xCc+gba2NqxZs2aarf/6r/+K7u5ulMvlrdsJPny8QPiEyMdOiXq9jt///vc48MADMWfOnGd9XrVaxYknnoijjz4aP/nJT/Cxj30MALB8+XK8/OUvx1e+8hX8+te/xoc//GH85S9/wRFHHIFarQYAOPLII/Gyl70M11133bTrXnvttTjooINw0EEHAQBe97rX4b777sOVV16JO+64A1/5ylfwspe9DGNjY+6cD3/4wzjrrLMwODiIG264AbfddhvOPfdcrF692h3zbOzaEv7rv/4Lxx13HDKZDL7zne/glltuQVdXF17zmtf4pMiHDx8+dlDU63VMTEygVqth7dq1uPTSS1EoFHDmmWc+47n/3//3/yEcDuPGG2/ElVdeiTvvvBNnn32255jHH38cr3vd63D99dfjl7/8JS699FLccsstTn1StPrOPO+889DW1oavfe1rnmNHRkZw00034e1vfztisdgL6wQfPrY2mj587IRYv359E0DzjDPOmPbexMREs1aruZ9Go9FsNpvNc889twmg+a1vfetpr91oNJq1Wq25evXqJoDmT37yE/fet7/97SaA5v333+9e+7//+78mgOZ3vvOdZrPZbA4PDzcBNL/4xS9u8R4rVqxohkKh5llnnfWs2/xs7Fq5cmWz2Ww2C4VCs6urq3nCCSd4rlGv15v77rtv8+CDD37W9/Xhw4cPH9se/By3P9FotPnlL3/ZcyyA5kc+8pFp51544YWe46688somgObQ0FDLe/J75a677moCaD744IPuvaf7zjz33HObfX19zUql4l77j//4j2YwGHTfQz587EjwFSIfLzoccMABCIfD7ufqq6/2vH/KKadMO2fjxo04//zzMX/+fLS1tSEcDmPhwoUAgEcffdQd9+Y3vxl9fX0eleiaa65Bb28vTj/9dABAV1cXlixZgs997nP4/Oc/j/vvvx+NRsNzvzvuuAP1eh0XXXTR07bl2dpl8cc//hEjIyM499xzMTEx4X4ajQaOP/54/PWvf50WHuHDhw8fPmYe3/3ud/HXv/4Vf/3rX/GLX/wC5557Li666CJce+21z3juiSee6Pn/pS99KQB4Ig9WrFiBM888EwMDAwiFQgiHw3jlK18JoPX3SqvvzHe/+93YuHEjbr31VgBAo9HAV77yFfzLv/wLdtlll2fdVh8+thf8ogo+dkr09PQgHo97PuSJG2+8EcViEUNDQ9O+HBKJBDKZjOe1RqOB4447DuvWrcOHPvQhvOQlL0EymUSj0cChhx6KUqnkjo1GozjvvPNw9dVX43Of+xxqtRpuueUWvPe970U0GgUwGdv929/+Fh//+Mdx5ZVX4t/+7d/Q1dWFs846C5/61KeQTqexadMmAHjaKkHPxS6LDRs2AABOPfXULR4zMjKCZDK5xfd9+PDhw8f2x5577jmtqMLq1avx/ve/H2effTY6Ojq2eG53d7fnf34v8fsin8/jyCOPRCwWwyc/+UnstttuSCQSWLNmDU4++eRp3yutvjMB4GUvexmOPPJIXHfddTjrrLNw++23Y9WqVdPC6Hz42FHgEyIfOyVCoRCOPvpo/PrXv8bQ0JAnj2ivvfYCgJZ78gQCgWmvPfzww3jwwQdxww034Nxzz3WvP/HEEy3vfcEFF+Czn/0svvWtb6FcLmNiYgLnn3++55iFCxe64gjLli3DLbfcgo9+9KOoVqv46le/it7eXgDA2rVrMX/+/Jb3ea52KXp6egBMqldbqkbU39//jNfx4cOHDx8zj5e+9KX41a9+hWXLluHggw9+3tf53e9+h3Xr1uHOO+90qhAAT36rotV3JnHJJZfgtNNOw9/+9jdce+212G233XDsscc+b9t8+NiW8AmRj50Wl19+OX7xi1/g/PPPxw9/+ENPBZ7nAn7gcyWN2NJK15w5c3Daaafhy1/+MqrVKk444QQsWLBgi9ffbbfd8MEPfhA/+tGP8Le//Q0AcNxxxyEUCuErX/kKXv7yl28VuxSHH344Ojo68Mgjj+Diiy9+xuN9+PDhw8eOC1Yo5WLa88UL+V6xeOMb34gFCxbg3/7t33DXXXfhC1/4wtMSKB8+ZhI+IfKx0+Lwww/Hddddh3e9613Yf//98c53vhN77703gsEghoaG8KMf/QgAWsr9ij322ANLlizBZZddhmazia6uLvz0pz/FHXfcscVz3v3ud+OQQw4BMLmJnuKhhx7CxRdfjNNOOw277rorIpEIfve73+Ghhx7CZZddBgDYZZdd8IEPfACf+MQnUCqV8OY3vxnt7e145JFHMDw8jI997GPPyy4ilUrhmmuuwbnnnouRkRGceuqp6Ovrw6ZNm/Dggw9i06ZN+MpXvvKM1/Hhw4cPH9sXDz/8MCYmJgAAmzdvxn//93/jjjvuwBvf+EYsWrToBV37sMMOQ2dnJ84//3x85CMfQTgcxve//308+OCDz/laoVAIF110Ef793/8dyWQSb33rW1+QbT58bEv4hMjHTo3zzz8fL3/5y/GlL30JX/jCF7Bu3ToEAgHMmzcPhx12GH7729/i6KOPftprhMNh/PSnP8W73/1uV0701a9+NX7zm99sUfk5+OCDscsuuyAej7u9jIiBgQEsWbIEX/7yl7FmzRoEAgEsXrwYV199Nd71rne54z7+8Y9j1113xTXXXIOzzjoLbW1t2HXXXXHJJZc8b7sUZ599NhYsWIArr7wS5513HnK5HPr6+rDffvv5X1w+fPjwsYPibW97m/u7vb0
"text/plain": [
"<Figure size 1000x1000 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"img = cv.imread(\"img/lena.png\", cv.IMREAD_GRAYSCALE)\n",
"_, img_bin = cv.threshold(img, 100, 255, cv.THRESH_BINARY)\n",
"\n",
"plt.figure(figsize=[10,10])\n",
"plt.subplot(121) \n",
"plt.imshow(img, cmap='gray')\n",
"plt.title(\"Grayscale\")\n",
"plt.subplot(122)\n",
"plt.imshow(img_bin, cmap='gray')\n",
"plt.title(\"Binary\");"
]
},
{
"cell_type": "markdown",
"id": "795796a4",
"metadata": {},
"source": [
"Istnieją również [inne metody ręcznego progowania](https://docs.opencv.org/4.5.3/d7/d1b/group__imgproc__misc.html#gaa9e58d2860d4afa658ef70a9b1115576), które np. przycinają wartości do progu (w dokumentacji znajdują się wzory i przykładowe wykresy opisujące poszczególne typy operacji). Poniżej możemy zobaczyć wynik dla tych operacji:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "f4c60175",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1500x1000 with 12 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"_, img_bin = cv.threshold(img, 100, 255, cv.THRESH_BINARY)\n",
"_, img_bin_inv = cv.threshold(img, 100, 255, cv.THRESH_BINARY_INV)\n",
"_, img_trunc = cv.threshold(img, 100, 255, cv.THRESH_TRUNC)\n",
"_, img_to_zero = cv.threshold(img, 100, 255, cv.THRESH_TOZERO)\n",
"_, img_to_zero_inv = cv.threshold(img, 100, 255, cv.THRESH_TOZERO_INV)\n",
"\n",
"images = (img, img_bin, img_bin_inv, img_trunc, img_to_zero, img_to_zero_inv)\n",
"titles = (\"Grayscale\", \"Binary\", \"Binary Inverse\", \"Truncate\", \"To Zero\", \"To Zero Inverse\")\n",
"\n",
"plt.figure(figsize=[15,10])\n",
"\n",
"for i, (image, title) in enumerate(zip(images, titles)):\n",
" plt.subplot(231+i)\n",
" plt.imshow(image, cmap='gray')\n",
" plt.title(title)\n",
" plt.colorbar()"
]
},
{
"cell_type": "markdown",
"id": "880d9cd6",
"metadata": {},
"source": [
"Spójrzmy na słupki z zakresami wartości. Możemy zauważyć, że dla poszczególnych obrazów wartości minimalne i maksymalne biblioteka Matplotlib automatycznie przeskalowała do skrajnych wartości dla bieli i czerni. Aby na etapie wyświetlania usunąć to przekłamanie, musimy nieco zmienić funkcję `matplotlib.pyplot.imshow()` podając prawdziwe zakresy wartości:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "2e63a031",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1500x1000 with 12 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure(figsize=[15,10])\n",
"\n",
"for i, (image, title) in enumerate(zip(images, titles)):\n",
" plt.subplot(231+i)\n",
" plt.imshow(image, cmap='gray', vmin=0, vmax=255)\n",
" plt.title(title)\n",
" plt.colorbar()"
]
},
{
"cell_type": "markdown",
"id": "462814e3",
"metadata": {},
"source": [
"## Operacje morfologiczne\n",
"\n",
"Morfologia matematyczna jest narzędziem, które pozwala m.in. na uzupełnianie ubytków w uszkodzonych/zniekształconych obrazach lub wyciszanie (a czasem i usuwanie) prostych kształtów. Na początku omówimy proste operacje typu erozja i dylacja, a następnie ich złożenie. Dodajmy, że operacje te działają zasadniczo na wszystkich typach obrazów (nie tylko binarnych)."
]
},
{
"cell_type": "markdown",
"id": "b03f9b25",
"metadata": {},
"source": [
"### Element strukturyzujący, erozja i dylacja\n",
"\n",
"Na początku będziemy potrzebowali tzw. element strukturyzujący. Jest to binarna maska (mała macierz), najczęściej o nieparzystym wymiarze i zawierająca jakiś prosty, regularny kształt. Kształt ten może być dowolny, jednak w praktyce wykorzystywanych jest [kilka standardowych](https://docs.opencv.org/4.5.3/d4/d86/group__imgproc__filter.html#gac2db39b56866583a95a5680313c314ad). Do łatwego uzyskania elementu użyjemy funkcji [`cv.getStructuringElement()`](https://docs.opencv.org/4.5.3/d4/d86/group__imgproc__filter.html#gac342a1bb6eabf6f55c803b09268e36dc)."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "a3f15b79",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"kernel_ellipse = cv.getStructuringElement(cv.MORPH_ELLIPSE, (7, 7))\n",
"plt.imshow(kernel_ellipse, cmap='gray');"
]
},
{
"cell_type": "markdown",
"id": "19fc2684",
"metadata": {},
"source": [
"No, powiedzmy, że jest to elipsa ;) Tutaj użyliśmy dość dużego elementu o wymariach 7 na 7, jednak w praktyce może być on mniejszy.\n",
"\n",
"W jaki sposób możemy wykorzystać taki element strukturyzujący? Element strutkruryzujący jest maską binarną, którą możemy *przyłożyć* dla każdego piksela jakiegoś obrazu (najczęściej przykłada się go centralnie do piksela). Białe piksele maski mówią nam które sąsiadujące piksele powinniśmy wziąć w danym momencie pod uwagę. Mając wartości tych pikseli, możemy policzyć ich wartość minimalną (erozja) lub maksymalną (dylacja) i ustawić w nowym obrazie na współrzędznych danego piksela. Wykorzystuje się tutaj odpowiednio funkcje [`cv.erode()`](https://docs.opencv.org/4.5.3/d4/d86/group__imgproc__filter.html#gaeb1e0c1033e3f6b891a25d0511362aeb) i [`cv.dilate()`](https://docs.opencv.org/4.5.3/d4/d86/group__imgproc__filter.html#ga4ff0f3318642c4f469d0e11f242f3b6c). Poniżej możemy zobaczyć działanie na klasycznym przykładzie z monetami:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "45748934",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAz8AAAJ6CAYAAAAGt/woAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOx9d5hURfb22zlOzgMzwww5CQqioC6uAdaECqIiLqjoori6rqKrrjkiBvAnimENGAARxRVFV3TNKAJKkjDDwDA5T0/n3N8f81VtdU3V7R4FAb3v8/TT3ffWrXzvPe85p05pYrFYDCpUqFChQoUKFSpUqFDxG4f2UFdAhQoVKlSoUKFChQoVKn4NqORHhQoVKlSoUKFChQoVvwuo5EeFChUqVKhQoUKFChW/C6jkR4UKFSpUqFChQoUKFb8LqORHhQoVKlSoUKFChQoVvwuo5EeFChUqVKhQoUKFChW/C6jkR4UKFSpUqFChQoUKFb8LqORHhQoVKlSoUKFChQoVvwuo5EeFChUqVKhQoUKFChW/C6jkR8VvHlu3bsWsWbPQt29fWCwWWCwW9O/fH7Nnz8bGjRsPdfV+FbzyyivQaDSoqqo61FVRoUKFChU/A+Q5zn5ycnJw8skn4/33349Lq9FocM899xyaiqpQcZhDf6groELFwcRzzz2Hv/71rxg4cCD+9re/YejQodBoNNi5cyeWLVuGY489Fnv27EHfvn0PdVVVqFChQoWKhHj55ZcxaNAgxGIxNDY2YtGiRTjnnHPw3nvv4ZxzzgEAfPvtt+jdu/chrqkKFYcnVPKj4jeLb775BnPmzMFZZ52FlStXwmg00nOnnHIKrr32Wrz11luwWCzSPLxeL6xW669RXRUqVKhQoSIhhg0bhtGjR9P/f/rTn5CRkYFly5ZR8nP88ccfkrqp70wVRwJUtzcVv1k89NBD0Ol0eO655+KID4upU6eisLAQAHDZZZfBbrdj27ZtmDBhAlJSUnDqqacCANauXYtzzz0XvXv3htlsRr9+/TB79my0trbSvL766itoNBosW7asWzmvvvoqNBoNNmzYAADYu3cvLr74YhQWFsJkMiEvLw+nnnoqNm/eHHfd0qVLMXbsWNjtdtjtdowcORIvvvgiPZ9MvZTwySef4NRTT0VqaiqsVitOOOEEfPrpp0ldq0KFChUqDj3MZjOMRiMMBgM9xru9EZe5zz77DNdccw2ys7ORlZWFyZMno76+Pi6/N998ExMmTEBBQQEsFgsGDx6MW2+9FR6PJy6d7J15//33Q6/Xo6ampltdr7jiCmRlZcHv9x/YTlChogdQyY+K3yQikQg+++wzjB49GgUFBUlfFwwGMWnSJJxyyin497//jXvvvRcAUFlZibFjx2Lx4sX4+OOPcdddd2H9+vU48cQTEQqFAAAnnXQSjj76aDz99NPd8l20aBGOPfZYHHvssQCAM888E5s2bcL8+fOxdu1aLF68GEcffTQcDge95q677sL06dNRWFiIV155BatWrcLMmTOxf/9+miaZesnw+uuvY8KECUhNTcWSJUuwYsUKZGZmYuLEiSoBUqFChYrDFJFIBOFwGKFQCLW1tbjhhhvg8XhwySWXJLz2yiuvhMFgwNKlSzF//nx8/vnnuPTSS+PSVFRU4Mwzz8SLL76Ijz76CDfccANWrFhBrUosRO/M2bNnQ6/X47nnnotL297ejuXLl2PWrFkwm82/rBNUqPgliKlQ8RtEY2NjDEDs4osv7nYuHA7HQqEQ/USj0VgsFovNnDkzBiD20ksvKeYdjUZjoVAotn///hiA2L///W967uWXX44BiP3444/02Pfffx8DEFuyZEksFovFWltbYwBiCxculJaxd+/emE6ni02fPj3pNidTr3379sVisVjM4/HEMjMzY+ecc05cHpFIJDZixIjYmDFjki5XhQoVKlQcfJDnOP8xmUyxZ555Ji4tgNjdd9/d7do5c+bEpZs/f34MQKyhoUFYJnmvfPHFFzEAsS1bttBzSu/MmTNnxnJzc2OBQIAee+SRR2JarZa+h1SoOFRQLT8qfncYNWoUDAYD/Tz++ONx56dMmdLtmubmZlx99dUoKiqCXq+HwWBASUkJAGDnzp003bRp05Cbmxtn/XnqqaeQk5ODiy66CACQmZmJvn374tFHH8UTTzyBH3/8EdFoNK68tWvXIhKJ4Nprr1VsS7L14rFu3Tq0t7dj5syZCIfD9BONRvGnP/0JGzZs6ObioEKFChUqDj1effVVbNiwARs2bMCHH36ImTNn4tprr8WiRYsSXjtp0qS4/0cddRQAxHkU7N27F5dccgny8/Oh0+lgMBgwfvx4AOL3iuid+be//Q3Nzc146623AADRaBSLFy/GWWedhT59+iTdVhUqDgbUgAcqfpPIzs6GxWKJe6ATLF26FF6vFw0NDd1eBFarFampqXHHotEoJkyYgPr6etx5550YPnw4bDYbotEojj/+ePh8PprWZDJh9uzZePzxx/Hoo48iFAphxYoVuPHGG2EymQB0+WJ/+umnuO+++zB//nzcdNNNyMzMxPTp0/Hggw8iJSUFLS0tAKAYracn9eLR1NQEALjgggukadrb22Gz2aTnVahQoULFr4/Bgwd3C3iwf/9+3HLLLbj00kuRnp4uvTYrKyvuP3kvkfeF2+3GSSedBLPZjAceeAADBgyA1WpFTU0NJk+e3O29InpnAsDRRx+Nk046CU8//TSmT5+O999/H1VVVd1c4VSoOBRQyY+K3yR0Oh1OOeUUfPzxx2hoaIhb9zNkyBAAEO55o9Fouh3bvn07tmzZgldeeQUzZ86kx/fs2SMs+5prrsG8efPw0ksvwe/3IxwO4+qrr45LU1JSQgMXlJeXY8WKFbjnnnsQDAbx7LPPIicnBwBQW1uLoqIiYTk9rReL7OxsAF1WKVlUoLy8vIT5qFChQoWKQ4+jjjoK//nPf1BeXo4xY8b87Hz++9//or6+Hp9//jm19gCIW4/KQvTOJLj++usxdepU/PDDD1i0aBEGDBiA008//WfXTYWKAwWV/Kj4zeK2227Dhx9+iKuvvhorV66Mi4TTE5CHO9GQEcg0WAUFBZg6dSqeeeYZBINBnHPOOSguLpbmP2DAANxxxx14++238cMPPwAAJkyYAJ1Oh8WLF2Ps2LEHpF4sTjjhBKSnp2PHjh3461//mjC9ChUqVKg4fEEihRLF2c/FL3mv8Dj//PNRXFyMm266CV988QUWLFigSJZUqPi1oJIfFb9ZnHDCCXj66adx3XXX4ZhjjsFf/vIXDB06FFqtFg0NDXj77bcBQGiyZzFo0CD07dsXt956K2KxGDIzM7F69WqsXbtWes3f/vY3HHfccQC6NqRjsXXrVvz1r3/F1KlT0b9/fxiNRvz3v//F1q1bceuttwIA+vTpg9tvvx33338/fD4fpk2bhrS0NOzYsQOtra249957f1a9COx2O5566inMnDkT7e3tuOCCC5Cbm4uWlhZs2bIFLS0tWLx4ccJ8VKhQoULFr4vt27cjHA4DANra2vDOO+9g7dq1OP/881FaWvqL8h43bhwyMjJw9dVX4+6774bBYMAbb7yBLVu29DgvnU6Ha6+9Fv/4xz9gs9lw2WWX/aK6qVBxoKCSHxW/aVx99dUYO3YsnnzySSxYsAD19fXQaDTo3bs3xo0bh08//RSnnHKKYh4GgwGrV6/G3/72NxrC87TTTsMnn3witeiMGTMGffr0gcVioXsFEeTn56Nv37545plnUFNTA41Gg7KyMjz++OO47rrraLr77rsP/fv3x1NPPYXp06dDr9ejf//+uP766392vVhceumlKC4uxvz58zF79my4XC7k5uZi5MiR6ktKhQoVKg5TXH755fR3WloaSktL8cQTT2DOnDm/OO+srCx88MEHuOmmm3DppZfCZrPh3HPPxZtvvoljjjmmx/lddNFF+Mc//oE///nPSEtL+8X1U6HiQEATi8Vih7oSKlT81rB161aMGDECTz/99AF5IalQoUKFChVHGp566ilcf/312L59O4YOHXqoq6NCBQCV/KhQcUB
"text/plain": [
"<Figure size 1000x800 with 4 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"coins = cv.imread(\"img/coins.png\", cv.IMREAD_GRAYSCALE)\n",
"_, coins_bin = cv.threshold(coins, 125, 255, cv.THRESH_BINARY)\n",
"\n",
"coins_eroded = cv.erode(coins_bin, kernel_ellipse, iterations=1)\n",
"coins_dilated = cv.dilate(coins_bin, kernel_ellipse, iterations=1)\n",
"\n",
"plt.figure(figsize=[10,8])\n",
"plt.subplot(221)\n",
"plt.imshow(coins, cmap='gray')\n",
"plt.title(\"Grayscale\")\n",
"plt.subplot(222)\n",
"plt.imshow(coins_bin, cmap='gray')\n",
"plt.title(\"Binary\")\n",
"plt.subplot(223)\n",
"plt.imshow(coins_eroded, cmap='gray')\n",
"plt.title(\"Eroded\")\n",
"plt.subplot(224)\n",
"plt.imshow(coins_dilated, cmap='gray')\n",
"plt.title(\"Dilated\");"
]
},
{
"cell_type": "markdown",
"id": "8353e60e",
"metadata": {},
"source": [
"Możemy zauważyć, że zastosowanie erozji spowodowało wypełnienie w większym lub mniejszym stopniu dziur w zbinaryzowanych monetach. Z kolei dylacja spowodowała prawie zaniknięcie obrazu. Użyliśmy tutaj jednej iteracji, jednak możliwe jest kilkukrotne wykonanie erozji lub dylacji.\n",
"\n",
"Poniżej możemy zobaczyć, że erozja i dylacja są w pewien sposób komplementarne:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "8ca44988",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAz8AAAJ6CAYAAAAGt/woAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOxdd5RURfb+OsfJkYEZZhhyliCC8sM1oIi4IkGSIuuqiK6AuohhMbCKK6Y1YRZZEQVzWBcxsWaCAiI5TGBy6umc+/cHp2qra6pe9yAI6PvO6dPd79Wr/N673723bmlisVgMKlSoUKFChQoVKlSoUPEbh/Z4V0CFChUqVKhQoUKFChUqfg2o5EeFChUqVKhQoUKFChW/C6jkR4UKFSpUqFChQoUKFb8LqORHhQoVKlSoUKFChQoVvwuo5EeFChUqVKhQoUKFChW/C6jkR4UKFSpUqFChQoUKFb8LqORHhQoVKlSoUKFChQoVvwuo5EeFChUqVKhQoUKFChW/C6jkR4UKFSpUqFChQoUKFb8LqORHxW8e27Ztw5VXXonS0lJYLBZYLBZ069YN11xzDTZt2nS8q/erYPny5dBoNCgrKzveVVGhQoUKFUcA8hxnPzk5OTjzzDPxwQcfxKXVaDS46667jk9FVag4waE/3hVQoeJY4plnnsH111+PHj16YO7cuejTpw80Gg127tyJVatWYejQodi3bx9KS0uPd1VVqFChQoWKhHjppZfQs2dPxGIx1NbW4oknnsC4cePw3nvvYdy4cQCAb7/9Fp06dTrONVWh4sSESn5U/Gbx9ddfY86cORg7dizeeOMNGI1Geu6ss87CddddhzVr1sBisUjz8Hq9sFqtv0Z1VahQoUKFioTo27cvhgwZQv+ff/75yMjIwKpVqyj5Oe20045L3dR3poqTAarbm4rfLO677z7odDo888wzccSHxaRJk1BQUAAAuOKKK2C32/HTTz9h9OjRSElJwdlnnw0AWLduHf74xz+iU6dOMJvN6Nq1K6655ho0NjbSvL788ktoNBqsWrWqTTkrVqyARqPBxo0bAQAHDhzAlClTUFBQAJPJhLy8PJx99tnYsmVL3HWvvvoqhg8fDrvdDrvdjoEDB+KFF16g55OplxI++eQTnH322UhNTYXVasXpp5+OTz/9NKlrVahQoULF8YfZbIbRaITBYKDHeLc34jL3+eef49prr0V2djaysrJwySWXoLq6Oi6/119/HaNHj0aHDh1gsVjQq1cvLFy4EB6PJy6d7J25ePFi6PV6VFZWtqnrn/70J2RlZcHv9x/dTlChoh1QyY+K3yQikQg+//xzDBkyBB06dEj6umAwiIsuughnnXUW3n33Xdx9990AgP3792P48OFYtmwZPv74YyxatAjff/89zjjjDIRCIQDAyJEjccopp+DJJ59sk+8TTzyBoUOHYujQoQCACy64AJs3b8YDDzyAdevWYdmyZTjllFPgcDjoNYsWLcL06dNRUFCA5cuX4+2338bMmTNRXl5O0yRTLxleeeUVjB49GqmpqXj55ZexevVqZGZm4rzzzlMJkAoVKlScoIhEIgiHwwiFQjh06BDmzZsHj8eDadOmJbz2z3/+MwwGA1599VU88MAD+OKLLzBjxoy4NHv37sUFF1yAF154Af/5z38wb948rF69mlqVWIjemddccw30ej2eeeaZuLTNzc147bXXcOWVV8JsNv+yTlCh4pcgpkLFbxC1tbUxALEpU6a0ORcOh2OhUIh+otFoLBaLxWbOnBkDEHvxxRcV845Go7FQKBQrLy+PAYi9++679NxLL70UAxD78ccf6bENGzbEAMRefvnlWCwWizU2NsYAxB599FFpGQcOHIjpdLrY9OnTk25zMvU6ePBgLBaLxTweTywzMzM2bty4uDwikUhswIABsVNPPTXpclWoUKFCxbEHeY7zH5PJFHvqqafi0gKI3XnnnW2unTNnTly6Bx54IAYgVlNTIyyTvFfWr18fAxDbunUrPaf0zpw5c2YsNzc3FggE6LF//OMfMa1WS99DKlQcL6iWHxW/OwwePBgGg4F+HnroobjzEyZMaHNNfX09Zs+ejcLCQuj1ehgMBnTu3BkAsHPnTppu6tSpyM3NjbP+PP7448jJycGll14KAMjMzERpaSmWLl2Khx9+GD/++COi0WhceevWrUMkEsF1112n2JZk68Xjm2++QXNzM2bOnIlwOEw/0WgU559/PjZu3NjGxUGFChUqVBx/rFixAhs3bsTGjRvx0UcfYebMmbjuuuvwxBNPJLz2oosuivvfv39/AIjzKDhw4ACmTZuG/Px86HQ6GAwGjBo1CoD4vSJ6Z86dOxf19fVYs2YNACAajWLZsmUYO3YsiouLk26rChXHAmrAAxW/SWRnZ8NiscQ90AleffVVeL1e1NTUtHkRWK1WpKamxh2LRqMYPXo0qqur8be//Q39+vWDzWZDNBrFaaedBp/PR9OaTCZcc801eOihh7B06VKEQiGsXr0aN954I0wmE4DDvtiffvop7rnnHjzwwAO46aabkJmZienTp+Pee+9FSkoKGhoaAEAxWk976sWjrq4OADBx4kRpmubmZthsNul5FSpUqFDx66NXr15tAh6Ul5djwYIFmDFjBtLT06XXZmVlxf0n7yXyvnC73Rg5ciTMZjP+/ve/o3v37rBaraisrMQll1zS5r0iemcCwCmnnIKRI0fiySefxPTp0/HBBx+grKysjSucChXHAyr5UfGbhE6nw1lnnYWPP/4YNTU1cet+evfuDQDCPW80Gk2bY9u3b8fWrVuxfPlyzJw5kx7ft2+fsOxrr70W999/P1588UX4/X6Ew2HMnj07Lk3nzp1p4II9e/Zg9erVuOuuuxAMBvH0008jJycHAHDo0CEUFhYKy2lvvVhkZ2cDOGyVkkUFysvLS5iPChUqVKg4/ujfvz/Wrl2LPXv24NRTTz3ifD777DNUV1fjiy++oNYeAHHrUVmI3pkEN9xwAyZNmoQffvgBTzzxBLp3745zzz33iOumQsXRgkp+VPxmceutt+Kjjz7C7Nmz8cYbb8RFwmkPyMOdaMgIZBqsDh06YNKkSXjqqacQDAYxbtw4FBUVSfPv3r077rjjDrz55pv44YcfAACjR4+GTqfDsmXLMHz48KNSLxann3460tPTsWPHDlx//fUJ06tQoUKFihMXJFIoUZwdKX7Je4XH+PHjUVRUhJtuugnr16/HI488okiWVKj4taCSHxW/WZx++ul48skn8Ze//AWDBg3C1VdfjT59+kCr1aKmpgZvvvkmAAhN9ix69uyJ0tJSLFy4ELFYDJmZmXj//fexbt066TVz587FsGHDABzekI7Ftm3bcP3112PSpEno1q0bjEYjPvvsM2zbtg0LFy4EABQXF+O2227D4sWL4fP5MHXqVKSlpWHHjh1obGzE3XfffUT1IrDb7Xj88ccxc+ZMNDc3Y+LEicjNzUVDQwO2bt2KhoYGLFu2LGE+KlSoUKHi18X27dsRDocBAE1NTXjrrbewbt06jB8/HiUlJb8o7xEjRiAjIwOzZ8/GnXfeCYPBgJUrV2Lr1q3tzkun0+G6667DLbfcApvNhiuuuOIX1U2FiqMFlfyo+E1j9uzZGD58OP75z3/ikUceQXV1NTQaDTp16oQRI0bg008/xVlnnaWYh8FgwPvvv4+5c+fSEJ7nnHMOPvnkE6lF59RTT0VxcTEsFgvdK4ggPz8fpaWleOqpp1BZWQmNRoMuXbrgoYcewl/+8hea7p577kG3bt3w+OOPY/r06dDr9ejWrRtuuOGGI64XixkzZqCoqAgPPPAArrnmGrhcLuTm5mLgwIHqS0qFChUqTlDMmjWL/k5LS0NJSQkefvhhzJkz5xfnnZWVhQ8//BA33XQTZsyYAZvNhj/+8Y94/fXXMWjQoHbnd+mll+KWW27BZZddhrS0tF9cPxUqjgY0sVgsdrwroULFbw3btm3DgAED8OSTTx6VF5IKFSpUqFBxsuHxxx/HDTfcgO3bt6NPnz7HuzoqVABQyY8KFUcV+/fvR3l5OW677TZUVFR
"text/plain": [
"<Figure size 1000x800 with 4 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"coins = cv.imread(\"img/coins.png\", cv.IMREAD_GRAYSCALE)\n",
"_, coins_bin = cv.threshold(coins, 125, 255, cv.THRESH_BINARY_INV)\n",
"\n",
"coins_eroded = cv.erode(coins_bin, kernel_ellipse, iterations=1)\n",
"coins_dilated = cv.dilate(coins_bin, kernel_ellipse, iterations=1)\n",
"\n",
"plt.figure(figsize=[10,8])\n",
"plt.subplot(221)\n",
"plt.imshow(coins, cmap='gray')\n",
"plt.title(\"Grayscale\")\n",
"plt.subplot(222)\n",
"plt.imshow(coins_bin, cmap='gray')\n",
"plt.title(\"Binary\")\n",
"plt.subplot(223)\n",
"plt.imshow(coins_eroded, cmap='gray')\n",
"plt.title(\"Eroded\")\n",
"plt.subplot(224)\n",
"plt.imshow(coins_dilated, cmap='gray')\n",
"plt.title(\"Dilated\");"
]
},
{
"cell_type": "markdown",
"id": "7fb63be6",
"metadata": {},
"source": [
"Element strukturyzujący w kształcie elipsy całkiem dobrze zadziałał w przypadku usunięcia dziur w owalnych kształtach. Z drugiej strony musimy być świadomi, że inne, arbitralne kształty mogą być przydatne w specjalnych zastosowaniach (np. pionowe lub ukośne linie/kreski)."
]
},
{
"cell_type": "markdown",
"id": "57e6d811",
"metadata": {},
"source": [
"### Otwarcie i zamknięcie\n",
"\n",
"Złożenie operacji dylacji i erozji może posłużyć np. do uzupełnienia przerw między kształtami lub wyciszenia drobnych szumów. Tzw. *otwarcie* dotyczy erozji, po której następuje dylacja, co w konsekwencji usuwa białe plamy i przerwy. Z kolei tzw. *zamknięcie* to dylacja, po której następuje erozja, i taka operacja usuwa czarne plamy i przerwy. Jeśli interesuje nas wypełnienie przerw, to takie złożenia operacji nie będą powodowały *rozrastania* obiektów. Użyjemy tutaj funkcji [`cv.morphologyEx()`](https://docs.opencv.org/4.5.3/d4/d86/group__imgproc__filter.html#ga67493776e3ad1a3df63883829375201f)."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "ed726508",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x1000 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"coins_opened = cv.morphologyEx(coins_bin, cv.MORPH_OPEN, kernel_ellipse, iterations=1)\n",
"\n",
"plt.figure(figsize=[10,10])\n",
"\n",
"plt.subplot(121)\n",
"plt.imshow(coins_bin, cmap='gray')\n",
"plt.title(\"Binary\")\n",
"plt.subplot(122)\n",
"plt.imshow(coins_opened, cmap='gray')\n",
"plt.title(\"Opening\");"
]
},
{
"cell_type": "markdown",
"id": "70a4d3ed",
"metadata": {},
"source": [
"### Zadanie 1\n",
"\n",
"Wczytaj obraz `text_no_ocr.png`, który zawiera fragment starych notatek (z przedmiotu \"E-gospodarka\" dra Michała Rena) posiadających zabezpieczenie przed dalszym przetwarzaniem. Spróbuj usunąć niechciane kształty (wynik nie musi być dokładny - może uzyskasz lepszy efekt?)."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "334ef7c2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.image.AxesImage at 0x7f91ab7c60a0>"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# miejsce na eksperymenty\n",
"\n",
"text = cv.imread(\"img/text_no_ocr.png\", cv.IMREAD_GRAYSCALE)\n",
"\n",
"kernel_ellipse = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))\n",
"text_closed = cv.morphologyEx(text, cv.MORPH_CLOSE, kernel_ellipse, iterations=1)\n",
"\n",
"text_sub = text.copy()\n",
"\n",
"rows,cols = text.shape\n",
"\n",
"for r in range(rows):\n",
" for c in range(cols):\n",
" if text_closed[r,c] < 200 and text[r,c] < 200:\n",
" text_sub[r,c] = 255\n",
"\n",
"plt.imshow(text_sub, cmap='gray')"
]
},
{
"cell_type": "markdown",
"id": "702de10a",
"metadata": {},
"source": [
"![Przykładowy wynik](img/text_no_ocr_sample_result.png)"
]
},
{
"cell_type": "markdown",
"id": "9aa0c742",
"metadata": {},
"source": [
"## Analiza połączonych komponentów\n",
"\n",
"Jeśli na naszym obrazie binarnym posiadamy zwarte grupy obiektów, to możemy im nadać etykiety i je policzyć. Na poniższym zdjęciu możemy policzyć litery napisu:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "88183615",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"bologna = cv.imread(\"img/bologna.png\", cv.IMREAD_GRAYSCALE)\n",
"_, bologna_bin = cv.threshold(bologna, 127, 255, cv.THRESH_BINARY)\n",
"\n",
"plt.figure(figsize=[10,5])\n",
"\n",
"plt.imshow(bologna_bin, cmap='gray');"
]
},
{
"cell_type": "markdown",
"id": "9fda42a9",
"metadata": {},
"source": [
"Do nadania etykiet użyjemy funkcji [`cv.connectedComponents()`](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#gaedef8c7340499ca391d459122e51bef5):"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "d98a9973",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAvAAAAGiCAYAAACBCPIbAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB+o0lEQVR4nO3deXxU9bk/8M+ZPZlMJnsmISskgUAAJYiAUkVZRBGpVm21aKt1RXspervor5W2FlrbWr1aabFexRVrFcS6gVcFEVmVJSwBkkASyJB9T2Y9vz+4M5cACTNzzixn5vN+vealmcw5851wZuY5z3m+z1cQRVEEEREREREpgircAyAiIiIiIt8xgCciIiIiUhAG8ERERERECsIAnoiIiIhIQRjAExEREREpCAN4IiIiIiIFYQBPRERERKQgDOCJiIiIiBSEATwRERERkYIwgCciIiIiUhAG8EREREREIVJQUABBEM66LVy40Od9aII4PiIiIiIiOs327dvhcrm8P1dUVGDmzJm48cYbfd6HIIqiGIzBERERERHR0BYtWoR///vfOHz4MARB8GkbZuCJiIiIKOb09/fDbrfLsi9RFM8KvvV6PfR6/ZDb2e12vPrqq1i8eLHPwTvAAJ6IiIiIYkx/fz8KCwthtVpl2V9CQgK6u7sH3PfYY49hyZIlQ263Zs0atLe34wc/+IFfz8cSGiIiIiKKKZ2dnTCbzairq0NiYqLkfeXm5p61L18y8LNnz4ZOp8N7773n13MyA09EREREMclkMsFkMknahycXnpiY6NfJwLFjx/DJJ5/gnXfe8fs5GcATERERUUwSRRFSi1EC3f7FF19ERkYGrrnmGr+3ZR94IiIiIqIQcrvdePHFF3H77bdDo/E/n84MPBERERHFpHBl4D/55BPU1tbijjvuCOg5GcATERERUUwKVwA/a9YsSc/LEhoiIiIiIgVhBp6IiIiIYlI4J7FKwQCeiIiIiGKSUgN4ltAQERERESkIM/BEREREFJOUmoFnAE9EREREMUmpATxLaIiIiIiIFIQZeCIiIiKKSUrNwDOAJyIiIqKYpNQAniU0REREREQKwgw8EREREcUkpWbgGcATERERUUxSagDPEhoiIiIiIgVhBp6IiIiIYpJSM/AM4ImIiIgoJik1gGcJDRERERGRgjADT0REREQxSakZeAbwRERERBSTlBrAs4SGiIiIiEhBmIEnIiIiopik1Aw8A3giIiIiiklKDeBZQkNEREREpCDMwBMRERFRzApHBl0qBvBEREREFJNYQkNEREREREHHDDwRERERxSSlZuAZwBMRERFRTFJqAM8SGiIiIiIiBWEGnoiIiIhiklIz8AzgiYiIiCgmKTWAZwkNEREREZGCMANPRERERDFJqRl4BvBEREREFJOUGsCzhIaIiIiISEGYgSciIiKimKTUDDwDeCIiIiKKSUoN4FlCQ0RERESkIMzAExEREVFMUmoGngE8EREREcUkpQbwLKEhIiIiIlIQZuCJiIiIKCYpNQPPAJ6IiIiIYpJSA3iW0BARERERKQgz8EREREQUk5iBJyIiIiJSEE8AL/Xmr+PHj+P73/8+UlNTER8fjwsuuAA7d+70eXtm4ImIiIiIQqStrQ2XXHIJpk+fjg8//BAZGRmoqqpCUlKSz/tgAE9EREREMSkcJTR/+MMfkJubixdffNF7X0FBgV/7YAkNEREREcUkOUtoOjs7B9xsNts5n3Pt2rWYOHEibrzxRmRkZODCCy/E888/79e4GcATEREREUmUm5sLs9nsvS1btuycj6uursby5ctRXFyMjz/+GPfeey9+/OMf4+WXX/b5uVhCQ0REREQxS64uMnV1dUhMTPT+rNfrz/k4t9uNiRMnYunSpQCACy+8EPv27cPy5ctx2223+fRczMATERERUUySs4QmMTFxwG2wAD4rKwujR48ecF9paSlqa2t9HjcDeCIiIiKiELnkkktQWVk54L5Dhw4hPz/f532whIaIiIiIYlI4utD85Cc/wdSpU7F06VLcdNNN2LZtG1asWIEVK1b4vA9m4ImIiIgoJoVjIaeLLroIq1evxhtvvIGysjL89re/xVNPPYVbb73V530wA09EREREFEJz587F3LlzA96eATwRERERxaRwlNDIgQE8EREREcUkpQbwrIEnIiIiIlIQZuCJiIiIKCYpNQPPAJ6IiIiIYpJSA3iW0BARERERKQgz8EREREQUk5SagWcAT0REREQxSakBPEtoiIiIiIgUhBl4IiIiIopJSs3AM4AnIiIiopik1ACeJTRERERERArCDDwRERERxSSlZuAZwBMRERFRTFJqAM8SGiIiIiIiBWEGnoiIiIhiklIz8AzgiYiIiCgmKTWAZwkNEREREZGCMANPRERERDFJqRl4BvBEREREFJOUGsCzhIaIiIiISEHCGsA/99xzKCwshMFgQHl5Ob744otwDoeIiIiIYownCx/oLRzCFsC/+eabWLRoER599FF88803mDZtGubMmYPa2tpwDYmIiIiIYojU4D1cQXzYAvgnn3wSd955J370ox+htLQUTz31FHJzc7F8+fJwDYmIiIiIKOKFZRKr3W7Hzp078fOf/3zA/bNmzcLmzZvPerzNZoPNZvP+7Ha70draitTUVAiCEPTxEhEREZF/RFFEV1cXsrOzoVJF5rRLpU5iDUsA39zcDJfLhczMzAH3Z2Zmwmq1nvX4ZcuW4de//nWohkdEREREMqmrq0NOTk64h3FOSg3gw3o6dGb2XBTFc2bUf/GLX6Cjo8N7Y508ERERkTKYTKZwDyHqhCUDn5aWBrVafVa2vbGx8aysPADo9Xro9fpQDY+IiIiIZBLJ5c7MwPtBp9OhvLwc69evH3D/+vXrMXXq1HAMiYiIiIhijFK70IRtJdbFixdjwYIFmDhxIqZMmYIVK1agtrYW9957b7iGREREREQU8cIWwN98881oaWnBb37zGzQ0NKCsrAwffPAB8vPzwzUkIiIiIoohSi2hCVsADwD3338/7r///nAOgYiIiIhilFID+MhsyklEREREROcU1gw8EREREVG4KDUDzwCeiIiIiGKSUgN4ltAQERERESkIM/BEREREFJOUmoFnAE9EREREMUmpATxLaIiIiIiIFIQZeCIiIiKKSUrNwDOAJyIiIqKYxACeiIiIKAQEQfD+fziCJ6JwYwBPREREEUmtVkOlUkGn00Gr1UKr1UKtVkOr1UIQBLhcLjQ0NMDtdod7qKRQzMATERERBUAQBGg0Guh0Ouj1egiCAIPBAK1WC5VKBZXq3D03HA5HiEdK0UapATy70BAREVFYJCYmIisrCzk5OcjNzUVWVhZSUlKQnJyMuLg4aDSaQYN3QJ7giyjUlixZAkEQBtwsFotf+2AGnoiIiEJOpVIhJSUFGg1DEQqfcGXgx4wZg08++cT7s1qt9mt7vmuIiIiIKCaFK4DXaDR+Z91PxxIaIiIiCjnPBFWiaNHZ2TngZrPZBn3s4cOHkZ2djcLCQnz3u99FdXW1X8/Fdw4RERGFnBwBvMvlYg08SebJwgd688jNzYXZbPbeli1bds7nu/jii/Hyyy/j448/xvPPPw+r1YqpU6eipaXF5zGzhIaIiIgUiV1oSCo5S2jq6uqQmJjovV+v15/z8XPmzPH+/9ixYzFlyhSMGDECK1euxOLFi316TgbwREREFHKnL8YUKK1WK8NIiOSRmJg4IID3ldFoxNixY3H48GGft2EJDREREYWcTqeTvA+XyyXDSCiWSS2fkSODb7PZcODAAWRlZfm8DQN4IiKiCJGQkIDU1NSYmNzpb9u8c+EKrCRVOAL4hx9+GBs2bEBNTQ22bt2K73znO+js7MTtt9/u8z5YQkNERBQh4uLiYDabodfrcfLkSWaYiaJQfX09vve976G5uRnp6emYPHkytmzZgvz8fJ/3wQCeiEhGgiBAq9VCEAQYjUY4nU6YzWbEx8fD5XKhq6vLm61xu93o7u6Gw+FgoEYA/q+mOz4+HpmZmVEdxMtRA08kVTj6wK9atUrS8wEM4ImIAiYIAtRqNeLi4pC
"text/plain": [
"<Figure size 1000x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"_, bologna_labels = cv.connectedComponents(bologna_bin)\n",
"\n",
"plt.figure(figsize=[10,5])\n",
"\n",
"plt.imshow(bologna_labels, cmap='gray')\n",
"plt.colorbar();"
]
},
{
"cell_type": "markdown",
"id": "fccd4605",
"metadata": {},
"source": [
"Zauważmy, że wynikowy obraz ma 8 etykiet, gdzie 0 oznacza tło, a kolejne siedem są przypisane do poszczególnych liter. Możemy wyświetlić poszczególne fragmenty obrazu dotyczące danej etykiety:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "0754cee5",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA9oAAAIZCAYAAABZHEfpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAA9hAAAPYQGoP6dpAACpeklEQVR4nOzdd3hT1f8H8HeSpulOF90UShkKBVQQZMiWLcoGEVBQQQREQUVRyxJwwlcEUWQpCIgiguIAZQrIEBWKCAVKC3TT3SZNk/P7g4f8KE3StL0ho+/X85zn+/Xem3PPScin+dx7zzkyIYQAEREREREREUlCbu8GEBEREREREbkSJtpEREREREREEmKiTURERERERCQhJtpEREREREREEmKiTURERERERCQhJtpEREREREREEmKiTURERERERCQhJtpEREREREREEmKiTURERERERCQhJtpkM2vXroVMJsPx48clqU8mk2Hy5MmS1HVrnbNnz67263U6HebMmYP69etDpVLhrrvuwtKlS6VrIBG5pNoQH19//XX0798fkZGRkMlkeOKJJyRrGxG5LlePjydOnMBzzz2H5s2bw9fXF6GhoejRowd+++03SdtI9sdEm6gGJk2ahIULF+K5557Dzz//jIEDB+L555/HggUL7N00IiK7Wrx4MbKzszFgwAC4u7vbuzlERA5h48aNOHr0KMaNG4fvvvsOn332GVQqFbp3747PP//c3s0jCbnZuwFEziohIQGrVq3CW2+9hZdeegkA0KVLF2RnZ2P+/PmYOHEiAgMD7dxKIiL7KCgogFx+43r+F198YefWEBE5hpdffhnvvfdeuW19+/bFfffdh7lz52LMmDF2ahlJjXe0ya40Gg2mT5+Oe+65B2q1GoGBgWjXrh2+++47s6/55JNP0LhxY6hUKjRt2hSbNm2qcExaWhomTJiAqKgouLu7IyYmBnPmzEFZWZlkbd+2bRuEEHjyySfLbX/yySdRUlKCn376SbJzEVHt48zxEYAxySYikpozx8eQkJAK2xQKBVq1aoWUlBTJzkP2xzvaZFdarRbXr1/HjBkzEBkZidLSUuzevRuDBg3CmjVrKlzV2759O/bs2YO5c+fC29sby5cvx8iRI+Hm5oYhQ4YAuBEk27RpA7lcjjfffBOxsbE4fPgw5s+fj6SkJKxZs8Zim+rXrw8ASEpK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
"text/plain": [
"<Figure size 1200x700 with 8 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"bologna_n = bologna_labels.max()\n",
"\n",
"plt.figure(figsize=[12,7])\n",
"\n",
"for i in range(bologna_n+1):\n",
" plt.subplot(331+i)\n",
" plt.imshow(bologna_labels==i, cmap='gray')\n",
" plt.title(f\"Label: {i}\")"
]
},
{
"cell_type": "markdown",
"id": "1a63dd4c",
"metadata": {},
"source": [
"Do wygodnego wyświetlenia pokolorowanych etykiet możemy użyć map kolorów. Pracując z biblioteką Matplotlib możemy wyświetlić taki obraz wprost i użyć ew. odpowiedniej [mapy kolorów](https://matplotlib.org/stable/tutorials/colors/colormaps.html), np.:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "2b02eb5f",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABUkAAAGiCAYAAADa0EdrAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAA9hAAAPYQGoP6dpAADZH0lEQVR4nOzdd5xkZZk+/Os551QOXd3VOU1PzpEZGIacJaooCioIrisIKoi4rPjT1XUXUNd1dxUQ2JWgryioRAXJAgLCDEzOeXp6ZjqHylXnPO8fTTfT01Wnqit1ur5+6oPTVSdUh3rq3HUHIaWUICIiIiIiIiIiIpqklNE+ASIiIiIiIiIiIqLRxCApERERERERERERTWoMkhIREREREREREdGkxiApERERERERERERTWoMkhIREREREREREdGkxiApERERERERERERTWoMkhIREREREREREdGkxiApERERERERERERTWoMkhIREREREREREdGkxiApERERERERERERTWoMkhIRUV41NTVBCDHsdsMNN4z2qREREY1pXEOJiIiyk481VCvg+RER0ST07rvvQtf1wX9v3LgR55xzDi677LJRPCsiIqKxj2soERFRdvKxhgoppSzEyREREQHATTfdhGeeeQY7duyAEGK0T4eIiGjc4BpKRESUnWzWUGaSEhFNUJFIBLFYLC/7klIOW1hsNhtsNpvpdrFYDL/+9a9x88038+KOiIjGDa6hRERE2RnPayiDpEREE1AkEsHUKW4cbtXTPzgDbrcbgUBgyNf+5V/+Bd/73vdMt3viiSfQ3d2Nq6++Oi/nQUREVGiRSARTp07F4cOH87I/rqFERDRZ9K+h1Th8uCcv+yv2GspyeyKiCai3txclJSXYt6YJXk9uM/p6+wxMOW4vDhw4AK/XO/j1TD7BO++882C1WvH000/ndA5ERETFMrCGHrvuZbuvhoYGrqFERDQpDKyhew/8N7xeR477CqOp4cairqHMJCUimsDcHgG3J7cSPQP923u93hFdLO7btw8vvvgi/vjHP+Z0fCIiotHg8Xjg8Xhy2sdAPgrXUCIimkzcbhvcbvNAZjqGYQAo7hrKICkR0QSmSwN6jvUCujSy2u6BBx5AZWUlLrzwwtxOgIiIaBRIKZFr0V2223MNJSKi8UzKBKRM5LyPbOSyhuZWg0lERJSEYRh44IEH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
"text/plain": [
"<Figure size 1700x500 with 6 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure(figsize=[17,5])\n",
"\n",
"plt.subplot(131)\n",
"plt.imshow(bologna_labels)\n",
"plt.title(\"Default\")\n",
"plt.colorbar()\n",
"plt.subplot(132)\n",
"plt.imshow(bologna_labels, cmap='gray')\n",
"plt.colorbar()\n",
"plt.title(\"Gray\")\n",
"plt.subplot(133)\n",
"plt.imshow(bologna_labels, cmap='inferno')\n",
"plt.colorbar()\n",
"plt.title(\"Inferno\");"
]
},
{
"cell_type": "markdown",
"id": "e37f716a",
"metadata": {},
"source": [
"Biblioteka OpenCV również posiada obsługę map kolorów, co może być pomocne gdybyśmy chcieli np. wyeksportować obraz. Na początku możemy przekonwertować obraz do przedziału `[0; 255]` (znajdujemy minimalną i maksymalną wartość przy pomocy [`cv.minMaxLoc()`](https://docs.opencv.org/4.5.3/d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707)), a następnie używamy funkcji [`cv.applyColorMap()`](https://docs.opencv.org/4.5.3/d3/d50/group__imgproc__colormap.html#gadf478a5e5ff49d8aa24e726ea6f65d15) podając wybraną [mapę](https://docs.opencv.org/4.5.3/d3/d50/group__imgproc__colormap.html#ga9a805d8262bcbe273f16be9ea2055a65) i otrzymując obraz BGR, np.:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "91f86157",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAADoCAYAAADFeh8YAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAA9hAAAPYQGoP6dpAABnEklEQVR4nO3deZwcVbn4/8+ppdfp6dnXrISEJQlbwLAJkSWAIiAKCoqguLJ4I/BVkZ9fQP2CcK/IvaIoioAgoF5BURAJSwIYIBCWkAAhkD2ZyWTW7pleq+r8/uhkkklm6erpnu5Jzvv1mheku7r7dFd31VPnPOc5QkopURRFURRFKSFasRugKIqiKIqyOxWgKIqiKIpSclSAoiiKoihKyVEBiqIoiqIoJUcFKIqiKIqilBwVoCiKoiiKUnJUgKIoiqIoSslRAYqiKIqiKCVHBSiKoiiKopQcFaAoipITIURWf4sWLRrV69x7770IIXjttdfy03BFUcYFo9gNUBRlfHrppZcG/PtHP/oRzz33HM8+++yA2w8++OCxbJaiKHsJFaAoipKTo48+esC/a2tr0TRtj9tzlU6nEULk5bkURRl/1BCPoigFM2XKFC655JI9bp83bx7z5s3r//eiRYsQQnD//fdz9dVX09zcjNfr5YMPPujfpquriy996UtUVVURDAb55Cc/yZo1a/Z47t/97ncceuih+Hw+qqqq+NSnPsW7775biLenKEoBqQBFUZSSce2117JhwwZ+9atf8fe//526urr++y699FI0TePBBx/k9ttvZ+nSpcybN4/u7u7+bW6++WYuvfRSZs6cySOPPMJ///d/s3z5co455hhWr15dhHekKEqu1BCPoiglY9q0afz5z38e9L4jjzySu+++u//fM2fO5LjjjuMXv/gF1113Hd3d3fzoRz/i4x//OA8++GD/dvPmzWP69OnccMMN/OEPfyj4e1AUJT9UD4qiKCXj05/+9JD3ff7znx/w72OPPZbJkyfz3HPPAZmk3Xg8vseQ0sSJEznppJN45pln8t5eRVEKRwUoiqKUjMbGxiHva2hoGPS2jo4OgP7/DvYcTU1N/fcrijI+qABFUZSC8fl8JJPJPW5vb28fdPvhZu20trYOelt1dTVA/39bWlr22G7Lli3U1NRk1WZFUUqDClAURSmYKVOmsHz58gG3vf/++6xatcr1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
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"val_min, val_max, _, _ = cv.minMaxLoc(bologna_labels)\n",
"bologna_labels_norm = 255 * (bologna_labels - val_min)/(val_max - val_min)\n",
"bologna_labels_norm = np.uint8(bologna_labels_norm)\n",
"\n",
"bologna_labels_turbo = cv.applyColorMap(bologna_labels_norm, cv.COLORMAP_TURBO)\n",
"plt.imshow(bologna_labels_turbo[:,:,::-1])\n",
"plt.title(\"Turbo\");"
]
},
{
"cell_type": "markdown",
"id": "6dac2bf4",
"metadata": {},
"source": [
"## Kontury"
]
},
{
"cell_type": "markdown",
"id": "046e4cfe",
"metadata": {},
"source": [
"W widzeniu komputerowym bardzo często chcemy nie tylko znaleźć pewne obiekty, ale również zaznaczyć ich obrys (kontury). Poniżej znajduje się kilka przykładów - będziemy co prawda działali na obrazie w skali odcieni szarości, aczkolwiek w pewnych zastosowaniach lepsze efekty dałaby praca na obrazie czarno-białym."
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "a785f7ff",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAz8AAAFoCAYAAAB5QUUlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAA9hAAAPYQGoP6dpAACWbklEQVR4nOzdd3xc9Z3v/9c500eakTQaadQlS7bc5G7jik0xBkMgdEKSXciSDSTALgu52SW5NwnJXtiwG8j+EsImN4UsCZsKoQQCNs0xxrj3JsmqVu9t+jm/P4wVy1VlpJnRfJ556BE0c+acj6zynff5NkXXdR0hhBBCCCGEmOTUaBcghBBCCCGEEBNBwo8QQgghhBAiIUj4EUIIIYQQQiQECT9CCCGEEEKIhCDhRwghhBBCCJEQJPwIIYQQQgghEoKEHyGEEEIIIURCkPAjhBBCCCGESAgSfoQQQgghhBAJQcKPEMDWrVu57bbbyM7Oxmw2k5WVxa233sqHH3447HN885vfRFGUUV3/vffeQ1EU3nvvvVG9frguu+wyLrvssnG9hhBCiIvbt28f99xzDyUlJdhsNmw2G9OmTePee+9lx44d0S5vQjz33HMoikJ1dXW0SxEJRMKPSHjf//73WblyJfX19Tz55JNs3LiR//iP/+DEiROsWrWKH/zgB8M6z+c///kRhaXTLVy4kA8//JCFCxeO6vVCCCHix49+9CMWLVrERx99xD/+4z/y2muv8ac//YmHHnqIgwcPsmTJEiorK6NdphCTkqLruh7tIoSIlg8++IDVq1dz7bXX8tJLL2E0GgefC4VC3HTTTbz++uts2rSJlStXnvMcAwMD2O32iSp5TE71+ox3D5MQQohzO9XuXHfddfz+97/HbDafdczvfvc7Vq5cSU5OzjnPEU/tzoU899xzfO5zn6OqqoqioqJolyMShPT8iIT2xBNPoCgKzz777JDgA2A0GvnhD3+Ioij827/9G/DXoW27du3i1ltvJS0tjZKSkiHPnc7v9/PII4+QlZWF3W5n9erV7Ny5k6KiIu6+++7B48417O3uu+8mOTmZiooKrr32WpKTk8nPz+eRRx7B7/cPuc5jjz3G0qVLcblcOJ1OFi5cyE9/+lPk3oYQQsSWxx9/HIPBwI9+9KNzBh+A2267bTD4nGoL9u/fz7p163A4HFx55ZUAbNiwgU9+8pPk5eVhtVqZOnUq9957L21tbYPn+stf/oKiKPzP//zPWdf57//+bxRFYfv27QAcP36cT33qU+Tk5GCxWPB4PFx55ZXs2bNnyOteeOEFli9fTnJyMsnJycyfP5+f/vSng88Pp64L2bhxI1deeSVOpxO73c7KlSt5++23h/VaIS7GePFDhJicwuEw7777LosXLyYvL++cx+Tn57No0SLeeecdwuHw4OM333wzn/rUp7jvvvvo7+8/7zU+97nP8Zvf/IavfOUrXHHFFRw6dIibbrqJnp6eYdUYDAa54YYbuOeee3jkkUfYtGkT3/72t0lJSeHrX//64HHV1dXce++9FBQUACfnMD344IOcOHFiyHFCCCGi5/R2Jzs7e9ivCwQC3HDDDdx77738y7/8C6FQCIDKykqWL1/O5z//eVJSUqiuruapp55i1apV7N+/H5PJxKWXXsqCBQt45plnuPPOO4ec9wc/+AFLlixhyZIlAFx77bWEw2GefPJJCgoKaGtrY8uWLXR1dQ2+5utf/zrf/va3ufnmm3nkkUdISUnhwIED1NTUDB4znLrO55e//CV/+7d/yyc/+Ul+8YtfYDKZ+NGPfsTVV1/Nm2++ORj8hBg1XYgE1dTUpAP6pz71qQsed8cdd+iA3tzcrH/jG9/QAf3rX//6Wcedeu6UgwcP6oD+z//8z0OO+5//+R8d0O+6667Bx959910d0N99993Bx+666y4d0H/7298Oef21116rT58+/bz1hsNhPRgM6t/61rf09PR0XdO0wefWrFmjr1mz5oJfrxBCiPFxoXYnFArpwWBw8OPU3+5TbcHPfvazC55b0zQ9GAzqNTU1OqC//PLLg8/9/Oc/1wF99+7dg49t27ZNB/Rf/OIXuq7reltbmw7o3/ve9857jePHj+sGg0H/zGc+M+yveTh1VVVV6bqu6/39/brL5dKvv/76IecIh8P6vHnz9EsuuWTY1xXifGTYmxAXoX88dOz0IW233HLLRV/3/vvvA3D77bcPefzWW289a4jd+SiKwvXXXz/ksblz5w65wwbwzjvvsHbtWlJSUjAYDJhMJr7+9a/T3t5OS0vLsK4lhBAiehYtWoTJZBr8+O53vzvk+XO1Oy0tLdx3333k5+djNBoxmUwUFhYCcPjw4cHj7rzzTjIzM3nmmWcGH/v+979PRkYGd9xxBwAul4uSkhL+/d//naeeeordu3ejadqQ623YsIFwOMz9999/wa9luHWdacuWLXR0dHDXXXcRCoUGPzRN45prrmH79u0XHG0hxHBI+BEJy+12Y7fbqaqquuBx1dXV2O12XC7X4GPDGa7Q3t4OgMfjGfK40WgkPT19WDXa7XasVuuQxywWCz6fb/Dzbdu2sW7dOgD+3//7f3zwwQds376dr33tawB4vd5hXUsIIcT4crvd2Gy2s25gwcl5NNu3b+eVV1456zm73Y7T6RzymKZprFu3jhdffJGvfOUrvP3222zbto2tW7cCQ//2WywW7r33Xl544QW6urpobW3lt7/9LZ///OexWCzAyZttb7/9NldffTVPPvkkCxcuJCMjg3/4h3+gt7cXgNbWVoDzDhUfaV1nam5uBk7eJDw9CJpMJr7zne+g6zodHR3nfb0QwyFzfkTCMhgMXH755fz5z3+mvr7+nH/M6+vr2blzJ+vXr8dgMAw+Ppz9fE4FnObmZnJzcwcfD4VCg8EoEn79619jMpl47bXXhgSlP/7xjxG7hhBCiLEzGAxcccUVvPXWWzQ2Ng65kTZr1iyAc+55c64258CBA+zdu5fnnnuOu+66a/DxioqKc177i1/8Iv/2b//Gz372M3w+H6FQiPvuu2/IMYWFhYMLFxw7dozf/va3fPOb3yQQCPBf//VfZGRkACfbxvz8/HNeZ6R1nc7tdgMne6WWLVt2zmPOvKEoxEhJz49IaI8++ii6rvOlL31pyIIGcHJi6he/+EV0XefRRx8d8blXr14NwG9+85shj//+978fnKwaCYqiYDQah4Qzr9fL888/H7FrCCGEiIxHH32UcDjMfffdRzAYHPV5TgWiUz03p/zoRz865/HZ2dncdttt/PCHP+S//uu/uP766wcXyTmX0tJS/vf//t/MmTOHXbt2AbBu3ToMBgPPPvtsxOo63cqVK0lNTeXQoUMsXrz4nB/nWyFPiOGSnh+R0FauXMn3vvc9HnroIVatWsUDDzxAQUEBtbW1PPPMM3z00Ud873vfY8WKFSM+9+zZs7nzzjv57ne/O3i37+DBg3z3u98lJSUFVY3MvYfrrruOp556ik9/+tN84QtfoL29nf/4j/84q+ERQggRfStXruSZZ57hwQcfZOHChXzhC19g9uzZqKpKY2Mjf/jDHwDOGuZ2phkzZlBSUsK//Mu/oOs6LpeLV199lQ0bNpz3Nf/4j//I0qVLAfj5z38+5Ll9+/bxwAMPcNtttzFt2jTMZjPvvPMO+/bt41/+5V8AKCoq4qtf/Srf/va38Xq93HnnnaSkpHDo0CHa2tp47LHHRlXXKcnJyXz/+9/nrrvuoqOjg1tvvZXMzExaW1vZu3cvra2tFwxeQgyHhB+R8B588EGWLFnCd7/7XR555BHa29txuVysWrWKzZs3s3z58lGf++c//znZ2dn89Kc/5emnn2b+/Pn89re/5ZprriE1NTUi9V9xxRX87Gc/4zvf+Q7XX389ubm5/P3f/z2ZmZncc889EbmGEEKIyLnvvvtYvnw5//mf/8nTTz9NQ0MDiqKQl5fHihUrePvtt7niiisueA6TycSrr77KP/7jP3LvvfdiNBpZu3YtGzduPG+PziWXXEJRURE2m+2sJaOzsrIoKSnhhz/8IXV1dSiKQnFxMd/97nd
"text/plain": [
"<Figure size 1000x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shapes = cv.imread(\"img/shapes.png\", cv.IMREAD_COLOR)\n",
"shapes_gray = cv.cvtColor(shapes, cv.COLOR_BGR2GRAY)\n",
"\n",
"plt.figure(figsize=[10,5])\n",
"\n",
"plt.subplot(121)\n",
"plt.imshow(shapes[:,:,::-1])\n",
"plt.title(\"Original\")\n",
"plt.subplot(122)\n",
"plt.imshow(shapes_gray, cmap='gray')\n",
"plt.title(\"Grayscale\");"
]
},
{
"cell_type": "markdown",
"id": "fe0024db",
"metadata": {},
"source": [
"Przy pomocy [`cv.findContours()`](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#gadf1ad6a0b82947fa1fe3c3d497f260e0) uzyskujemy kontury obiektów oraz opcjonalną macierz opisującą ich hierarchię. Drugi parametr funkcji opisuje [sposób wyznaczania konturów](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#ga819779b9857cc2f8601e6526a3a5bc71), a trzeci [algorytm aproksymacji konturów](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#ga4303f45752694956374734a03c54d5ff)."
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "b6b7b6fd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"No. of contours: 11\n"
]
}
],
"source": [
"shapes_contours, _ = cv.findContours(shapes_gray, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)\n",
"print(f\"No. of contours: {len(shapes_contours)}\")"
]
},
{
"cell_type": "markdown",
"id": "8fb4fa32",
"metadata": {},
"source": [
"Przy pomocy [`cv.drawContours()`](https://docs.opencv.org/4.5.3/d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc) możemy nanieść kontury na obraz. Zauważmy, że mamy tutaj oznaczone zewnętrzne i wewnętrzne kontury:"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "eb7fe829",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shapes_with_contours = shapes.copy()\n",
"\n",
"cv.drawContours(shapes_with_contours, shapes_contours, -1, (255,255,0), 2)\n",
"\n",
"plt.figure(figsize=[10,5])\n",
"plt.imshow(shapes_with_contours[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "bbe70d91",
"metadata": {},
"source": [
"Możemy również ograniczyć się tylko do zewnętrznych konturów (parametr `cv.RETR_EXTERNAL`):"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "dfab04dc",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"No. of contours: 9\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shapes_contours, _ = cv.findContours(shapes_gray, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)\n",
"print(f\"No. of contours: {len(shapes_contours)}\")\n",
"shapes_with_contours = shapes.copy()\n",
"\n",
"cv.drawContours(shapes_with_contours, shapes_contours, -1, (255,255,0), 2)\n",
"\n",
"plt.figure(figsize=[10,5])\n",
"plt.imshow(shapes_with_contours[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "0e0a0799",
"metadata": {},
"source": [
"Poniżej mamy zaznaczony obrys konturu wybranego obiektu, np. o indeksie 5:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "5756eaeb",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shapes_with_contours = shapes.copy()\n",
"\n",
"cv.drawContours(shapes_with_contours, shapes_contours, 5, (255,255,0), 2)\n",
"\n",
"plt.figure(figsize=[10,5])\n",
"plt.imshow(shapes_with_contours[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "05e6211d",
"metadata": {},
"source": [
"Poniżej możemy zobaczyć jak przy pomocy tzw. [momentów](https://en.wikipedia.org/wiki/Image_moment) są wyliczane środki ciężkości poszczególnych konturów. Każdy kontur jest również opisany żółtą etykietą liczbową, ale w związku z tym, że czasem mamy kontur zewnętrzny i wewnętrzny blisko siebie, to niektóre etykiety nakładają się na siebie. Dodatkowo, tym razem kontury wykryjemy z informacją o drzewiastej hierarchii (parametr `cv.RETR_TREE`, za chwilę opiszemy co tam się znajduje)."
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "2315e142",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shapes_contours, shapes_hierarchy = cv.findContours(shapes_gray, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)\n",
"shapes_with_contours = shapes.copy()\n",
"\n",
"cv.drawContours(shapes_with_contours, shapes_contours, -1, (255,255,0), 2)\n",
"\n",
"for idx, contour in enumerate(shapes_contours):\n",
" M = cv.moments(contour)\n",
" x = int(round(M[\"m10\"]/M[\"m00\"]))\n",
" y = int(round(M[\"m01\"]/M[\"m00\"]))\n",
" \n",
" cv.circle(shapes_with_contours, (x,y), 5, (255,255,255), -1)\n",
" cv.putText(shapes_with_contours, str(idx), (x+10, y+10), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 200, 255), 2)\n",
" \n",
"plt.figure(figsize=[10,5])\n",
"plt.imshow(shapes_with_contours[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "07e0820a",
"metadata": {},
"source": [
"W zmiennej `shapes_hierarchy` mamy macierz opisującą hierarchię konturów. Dla każdego wiersza (konturu) kolejne kolumny opisują odpowiednio: indeks następnego konturu, indeks poprzedniego konturu, indeks pierwszego dziecka oraz indeks rodzica (wartość ujemna oznacza, że dane pole nie ma zastosowania)."
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "894b7fb1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[[ 1 -1 -1 -1]\n",
" [ 2 0 -1 -1]\n",
" [ 3 1 -1 -1]\n",
" [ 5 2 4 -1]\n",
" [-1 -1 -1 3]\n",
" [ 6 3 -1 -1]\n",
" [ 7 5 -1 -1]\n",
" [ 8 6 -1 -1]\n",
" [ 9 7 -1 -1]\n",
" [-1 8 10 -1]\n",
" [-1 -1 -1 9]]]\n"
]
}
],
"source": [
"print(shapes_hierarchy)"
]
},
{
"cell_type": "markdown",
"id": "9311c0d9",
"metadata": {},
"source": [
"Przy pomocy [`cv.contourArea()`](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#ga2c759ed9f497d4a618048a2f56dc97f1) i [`cv.arcLength()`](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#ga8d26483c636be6b35c3ec6335798a47c) możemy policzyć odpowiednio pole powierzchni i obwód kształtu:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "a00e03ce",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Contour id 0: area = 1063.0, perimeter = 161.4\n",
"Contour id 1: area = 8017.5, perimeter = 390.0\n",
"Contour id 2: area = 375.0, perimeter = 133.0\n",
"Contour id 3: area = 1750.0, perimeter = 170.0\n",
"Contour id 4: area = 556.0, perimeter = 95.7\n",
"Contour id 5: area = 2917.0, perimeter = 244.7\n",
"Contour id 6: area = 729.5, perimeter = 185.6\n",
"Contour id 7: area = 1922.0, perimeter = 175.7\n",
"Contour id 8: area = 380.5, perimeter = 73.4\n",
"Contour id 9: area = 2596.5, perimeter = 191.6\n",
"Contour id 10: area = 407.0, perimeter = 75.6\n"
]
}
],
"source": [
"for idx, contour in enumerate(shapes_contours):\n",
" area = cv.contourArea(contour)\n",
" perimeter = round(cv.arcLength(contour, True), 1)\n",
" print(f\"Contour id {idx: >2}: area = {area: >6}, perimeter = {perimeter: >5}\")"
]
},
{
"cell_type": "markdown",
"id": "3873897e",
"metadata": {},
"source": [
"Dla znalezionych kształtów często chcemy wyznaczyć ramkę ograniczającą i możemy to zrobić na kilka sposobów. Poniżej przy pomocy [`cv.boundingRect()`](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#ga103fcbda2f540f3ef1c042d6a9b35ac7) i [`cv.rectangle()`](https://docs.opencv.org/4.5.3/d6/d6e/group__imgproc__draw.html#ga07d2f74cadcf8e305e810ce8eed13bc9) nanosimy prostokąty:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "54160020",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shapes_with_bb = shapes_with_contours.copy()\n",
"for contour in shapes_contours:\n",
" x,y,w,h = cv.boundingRect(contour)\n",
" cv.rectangle(shapes_with_bb, (x,y), (x+w,y+h), (255,0,255), 2)\n",
" \n",
"plt.figure(figsize=[10,5])\n",
"plt.imshow(shapes_with_bb[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "38d0f1f2",
"metadata": {},
"source": [
"Czasami wygodniej jest umieścić minimalny obrys prostokąta, co możemy uzyskać przy pomocy [`cv.minAreaRect()`](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#ga3d476a3417130ae5154aea421ca7ead9) i [`cv.boxPoints()`](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#gaf78d467e024b4d7936cf9397185d2f5c):"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "9184cd42",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shapes_with_bb = shapes_with_contours.copy()\n",
"for contour in shapes_contours:\n",
" rect = cv.minAreaRect(contour)\n",
" box_points = np.int0(cv.boxPoints(rect))\n",
" cv.drawContours(shapes_with_bb, [box_points], -1, (255,0,255), 2)\n",
" \n",
"plt.figure(figsize=[10,5])\n",
"plt.imshow(shapes_with_bb[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "e3c9d01b",
"metadata": {},
"source": [
"Poniżej mamy przykład z okręgiem przy pomocy [`cv.minEnclosingCircle()`](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#ga8ce13c24081bbc7151e9326f412190f1):"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "16f9d71b",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shapes_with_bb = shapes_with_contours.copy()\n",
"for contour in shapes_contours:\n",
" (x,y), radius = cv.minEnclosingCircle(contour)\n",
" cv.circle(shapes_with_bb, (int(x),int(y)), int(round(radius)), (255,0,255), 2)\n",
" \n",
"plt.figure(figsize=[10,5])\n",
"plt.imshow(shapes_with_bb[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "8128584a",
"metadata": {},
"source": [
"Możemy również umieścić elipsy przy pomocy [`cv.fitEllipse()`](https://docs.opencv.org/4.5.3/d3/dc0/group__imgproc__shape.html#gaf259efaad93098103d6c27b9e4900ffa), ale w tym przypadku kontur musi składać się z co najmniej 5 punktów:"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "dfee5d44",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shapes_with_bb = shapes_with_contours.copy()\n",
"for contour in shapes_contours:\n",
" if len(contour) < 5:\n",
" continue\n",
" ellipse = cv.fitEllipse(contour)\n",
" cv.ellipse(shapes_with_bb, ellipse, (255,0,255), 2)\n",
" \n",
"plt.figure(figsize=[10,5])\n",
"plt.imshow(shapes_with_bb[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "de2ca7bf",
"metadata": {},
"source": [
"## Wykrywanie obszarów/plam\n",
"\n",
"Do wykrywania obszarów/plam (ang. *blobs*) posiadających wspólne cechy (np. rozmiar, kształt, wartości pikseli) możemy użyć [`cv.SimpleBlobDetector_create()`](https://docs.opencv.org/4.5.3/d0/d7a/classcv_1_1SimpleBlobDetector.html#a1d7a06c8b8749207a978e42cd8d0cdf6), a następnie używamy metody `detect()`. W poniższym przykładzie użyjemy domyślnych wartości detektora."
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "1bb452fb",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABMIAAAG7CAYAAAAhYjkOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9eZhd11XnD3/vVHeeb92aq1QqTZZkW5ZkO3YSMhEn0B3ClA5hSAINnZAAoeH38IbQDQn0A7SB0JCJ0JCBDglJSAIZII7tzCSxZcuWbMuSNdQ83qHuPA/vH+Xv0rqnbklVsmRJ9lnPo6dUt849Z589rP3Za629tqXdbrdhiimmmGKKKaaYYooppphiiimmmGKKKc9xsV7tAphiiimmmGKKKaaYYooppphiiimmmGLKsyGmIcwUU0wxxRRTTDHFFFNMMcUUU0wxxZTnhZiGMFNMMcUUU0wxxRRTTDHFFFNMMcUUU54XYhrCTDHFFFNMMcUUU0wxxRRTTDHFFFNMeV6IaQgzxRRTTDHFFFNMMcUUU0wxxRRTTDHleSGmIcwUU0wxxRRTTDHFFFNMMcUUU0wxxZTnhZiGMFNMMcUUU0wxxRRTTDHFFFNMMcUUU54XYhrCTDHFFFNMMcUUU0wxxRRTTDHFFFNMeV6IaQgzxRRTTDHFFFNMMcUUU0wxxRRTTDHleSGmIcwUU0x5RnL8+HH81//6XzExMQG32w23242dO3fiLW95Cx566KGrXbxnRT72sY/BYrFgamrqahfFFFNMMcUUU0wx5ZoRMpL+19vbi5e+9KX48pe/3HGtxWLBu9/97i0/45vf/CYsFgv++Z//+TKV2hRTTHmui/1qF8AUU0y5fuXDH/4wfu3Xfg27d+/GO97xDuzbtw8WiwVPPvkkPvWpT+HWW2/FmTNnMDExcbWLaooppphiiimmmGLKVZKPfvSj2LNnD9rtNpaWlvD+978fr3nNa/DFL34Rr3nNa6528UwxxZTnmZiGMFNMMeWS5D/+4z/wtre9Df/pP/0n/PM//zN6enrkby9/+cvx9re/HZ/97Gfhdrs3vEepVILH43k2imuKKaaYYooppphiylWS/fv34/Dhw/L7q1/9aoTDYXzqU58yDWGmmGLKsy7m1khTTDHlkuSP//iPYbPZ8OEPf7jDCKblda97HQYHBwEAb37zm+Hz+fDYY4/hrrvugt/vxyte8QoAwL333ovXvva1GB4ehsvlwo4dO/CWt7wFyWRS7vWd73wHFosFn/rUp9Y95x/+4R9gsVhw5MgRAMC5c+fwMz/zMxgcHITT6URfXx9e8YpX4NFHH+343ic/+Unccccd8Pl88Pl8OHDgAP7+7/9e/r6Zcl1I7rvvPrziFa9AIBCAx+PBC1/4Qtx///2b+q4ppphiiimmmGLKc1VcLhd6enrgcDgueN3jjz+O1772tQiHw3C5XDhw4AA+/vGPd722Uqngt37rt9Df3w+3242XvOQleOSRRzqu2SwjmmKKKc9tMSPCTDHFlC1Ls9nEN77xDRw+fBgDAwOb/l6tVsOP/diP4S1veQve+c53otFoAADOnj2LO+64A7/8y7+MYDCIqakpvPe978WLXvQiPPbYY3A4HHjxi1+MW265BR/4wAfwhje8oeO+73//+3Hrrbfi1ltvBQD86I/+KJrNJu6++26Mjo4imUzie9/7HjKZjHzn93//9/FHf/RH+Mmf/En89m//NoLBIB5//HFMT0/LNZsp10byiU98Am984xvx2te+Fh//+MfhcDjw4Q9/GK961atwzz33iBHQFFNMMcUUU0wx5bkuzWYTjUYD7XYby8vL+LM/+zMUi0X87M/+7IbfOXXqFO68807E43H89V//NaLRKD7xiU/gzW9+M5aXl/E7v/M7Hde/613vwsGDB/F3f/d3yGazePe7342XvvSleOSRR7B9+3YAm2NEU0wx5XkgbVNMMcWULcrS0lIbQPtnfuZn1v2t0Wi06/W6/Gu1Wu12u91+05ve1AbQ/shHPnLBe7darXa9Xm9PT0+3AbT/9V//Vf720Y9+tA2g/cgjj8hnDz74YBtA++Mf/3i73W63k8lkG0D7//yf/7PhM86dO9e22Wztn/u5n9v0O2+mXJOTk+12u90uFovtSCTSfs1rXtNxj2az2b755pvbt91226afa4oppphiiimmmHK9ChnJ+M/pdLY/+MEPdlwLoP0Hf/AH8vvP/MzPtJ1OZ3tmZqbjuh/5kR9pezyediaTabfb7fY3vvGNNoD2wYMHhTvb7XZ7amqq7XA42r/8y7/cbrc3x4immGLK80PMrZGmmGLKZZVDhw7B4XDIv7/4i7/o+PtP/dRPrfvOysoK3vrWt2JkZAR2ux0OhwNjY2MAgCeffFKue8Mb3oB4PI4PfOAD8tn73vc+9Pb24vWvfz0AIBKJYGJiAn/2Z3+G9773vXjkkUfQarU6nnfvvfei2Wzi7W9/+wXfZbPlMsr3vvc9pNNpvOlNb0Kj0ZB/rVYLr371q3HkyBEUi8ULPtsUU0wxxRRTTDHluSL/8A//gCNHjuDIkSP493//d7zpTW/C29/+drz//e/f8Dtf//rX8YpXvAIjIyMdn7/5zW9GqVTC97///Y7Pf/ZnfxYWi0V+Hxsbw5133olvfOMbADbHiKaYYsrzQ0xDmCmmmLJlicVicLvdHdsIKZ/85Cdx5MgRfPGLX1z3N4/Hg0Ag0PFZq9XCXXfdhc9//vP4nd/5Hdx///148MEH8YMf/AAAUC6X5Vqn04m3vOUt+OQnP4lMJoNEIoHPfOYz+OVf/mU4nU4Aa0dv33///XjVq16Fu+++GwcPHkRvby9+4zd+A/l8HgCQSCQAAMPDwxu+41bKZZTl5WUAwE//9E93GAUdDgf+9//+32i320in0xt+3xRTTDHFFFNMMeW5JDfccAMOHz6Mw4cP49WvfjU+/OEP46677sLv/M7vbLgtMZVKdU3BwfyzqVSq4/P+/v511/b398t1m2FEU0wx5fkhZo4wU0wxZctis9nw8pe/HF/72tewuLjYASl79+4FAExNTa37nvbSUR5//HEcO3YMH/vYx/CmN71JPj9z5kzXZ//qr/4q/vRP/xQf+chHUKlU0Gg08Na3vrXjmrGxMUl6/9RTT+Ezn/kM3v3ud6NWq+Fv/uZv0NvbCwCYm5tb52W81HJpicViANai1V7wghd0vaavr++i9zHFFFNMMcUUU0x5rspNN92Ee+65B0899RRuu+22dX+PRqNYXFxc9/nCwgKA87xFWVpaWnft0tISotGo/H4xRjTFFFOeH2JGhJliiimXJL/7u7+LZrOJt771rajX65d8HxrHGNFF+fCHP9z1+oGBAbzuda/DBz/4QfzN3/wNXvOa12B0dHTD++/atQv/43/8D9x44404evQoAOCuu+6CzWbDhz70octWLi0vfOELEQqFcOLECfF+Gv9tdNKmKaaYYooppphiyvNBeFIjHZRGecUrXoGvf/3rYvii/MM//AM8Hs86Z+OnPvUptNtt+X16ehrf+9738NKXvrTr/bsxoimmmPL8EDMizBRTTLkkeeELX4gPfOAD+PVf/3UcPHgQ/+2//Tfs27cPVqsVi4uL+NznPgcA67ZCGmXPnj2YmJjAO9/5TrTbbUQiEXzpS1/Cvffeu+F33vGOd+D2228HAHz0ox/t+Nvx48fxa7/2a3jd616HnTt3oqenB1//+tdx/PhxvPOd7wQAbNu2De9617vwR3/0RyiXy3jDG96AYDCIEydOIJlM4j3vec8llYvi8/nwvve9D29605uQTqfx0z/904jH40gkEjh27BgSicQFjXCmmGKKKaaYYoopzyV5/PHH5bTwVCqFz3/+87j33nvxEz/xExgfH+/6nT/4gz/Al7/8ZbzsZS/D7//+7yMSieAf//Ef8ZWvfAV33303gsFgx/UrKyv4iZ/4CfzKr/wKstks/uAP/gAulwu/+7u/C2BzjGiKKaY8P8Q0hJliiimXLG9961txxx134K/+6q/wl3/5l1hYWIDFYsHw8DDuvPNO3H///Xj5y19+wXs4HA586Ut
"text/plain": [
"<Figure size 1500x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"blobs_gray = cv.imread(\"img/blobs.png\", cv.IMREAD_GRAYSCALE)\n",
" \n",
"blob_detector = cv.SimpleBlobDetector_create()\n",
"\n",
"keypoints = blob_detector.detect(blobs_gray)\n",
"\n",
"blobs_color = cv.cvtColor(blobs_gray, cv.COLOR_GRAY2BGR)\n",
" \n",
"for kp in keypoints:\n",
" x, y = kp.pt\n",
" x = int(round(x))\n",
" y = int(round(y))\n",
"\n",
" radius = int(round(kp.size/2))\n",
"\n",
" cv.circle(blobs_color, (x,y), radius, (0,0,255), 3)\n",
"\n",
"plt.figure(figsize=[15,5])\n",
"plt.subplot(121)\n",
"plt.imshow(blobs_gray, cmap='gray')\n",
"plt.title(\"Grayscale\")\n",
"plt.subplot(122)\n",
"plt.imshow(blobs_color[:,:,::-1])\n",
"plt.title(\"Blobs\");"
]
},
{
"cell_type": "markdown",
"id": "7f8071d0",
"metadata": {},
"source": [
"Parametry ustawia się poprzez atrybuty obiektu zwracanego przez [`cv.SimpleBlobDetector_Params()`](https://docs.opencv.org/4.5.3/d8/da7/structcv_1_1SimpleBlobDetector_1_1Params.html). Po ustawieniu parametrów obiekt z parametrami przekazuje się jako argument `cv.SimpleBlobDetector_create()`.\n",
"\n",
"Detektor działa następująco:\n",
"\n",
"1. Obraz źródłowy jest przekształcany do obrazów binarnych poprzez progowanie z wartościami odcięcia od `minThreshold` do `maxThreshold` z krokiem `thresholdStep`.\n",
"2. Dla każdego obrazu binarnego znajdowane są połączone komponenty przy pomocy `cv.findContours()` oraz obliczane są współrzędne ich środków.\n",
"3. Środki z kilku obrazów binarnych są grupowane na podstawie ich współrzędnych. Te, które znajdują się blisko siebie, odpowiadają jednej plamie/obszarowi (kontroluje się to poprzez parametr `minDistBetweenBlobs`).\n",
"4. Na podstawie wyznaczonych wcześniej grup obliczane są końcowe współrzędne środków plam/obszarów oraz ich promienie, tak by zwrócić je jako lokalizacje i rozmiary punktów kluczowych.\n",
"\n",
"Detektor dokonuje kilku filtracji zwracanych plam/obszarów. Poszczególne filtry ustawia się poprzez parametry `filterBy*` nadając im wartość `True` lub `False`. Można filtrować według:\n",
"\n",
"1. koloru (`filterByColor = True`), tj. następuje porównanie intensywności środka plamy/obszaru z obrazu binarnego do wartości ustawionej w `blobColor`; jeśli są różne, to plama/obszar jest odfiltrowana; wartość `blobColor = 0` wyodrębnia czarne plamy/obszary, a `blobColor = 255` jasne,\n",
"2. powierzchni (`filterByArea = True`), tj. plamy/obszary mają mieć powierzchnię między `minArea` a `maxArea`; np. ustawienie `minArea = 100` spowoduje odfiltrowanie plam/obszarów, których powierzchnia stanowi mniej niż 100 pikseli,\n",
"3. okrągłości (`filterByCircularity = True`), tj. miara okrągłości plamy/obszaru `4 * pi * pole powierzchni / obwód^2` ma być między `minCircularity` a `maxCircularity`; np. regularny sześciokąt ma większą okrągłość niż kwadrat; np. okrąg ma miarę `1.0`, a kwadrat ok. `0.785`,\n",
"4. inercji (`filterByInertia = True`), tj. jej wartość ma się znaleźć między `minInertiaRatio` a `maxInertiaRatio`; miara ta określa jak bardzo wydłużony jest dany kształt, np. dla okręgu wartość ta wynosi 1, dla elipsy mieści się w przedziale od 0 do 1, a dla linii wynosi 0; aby odfiltrować po inercji można ustawić `0 ≤ minInertiaRatio ≤ 1` oraz `maxInertiaRatio ≤ 1`,\n",
"5. wypukłości (`filterByConvexity = True`), tj. `pole powierzchni / pole powierzchni otoczki wypukłej` ma być między `minConvexity` a `maxConvexity`; aby odfiltrować po wypukłości można ustawić `0 ≤ minConvexity ≤ 1` oraz `maxConvexity ≤ 1`.\n",
"\n",
"Domyślne wartości parametrów są dostrojone do ekstrakcji ciemnych, okrągłych plam.\n",
"\n",
"Poniżej znajduje się przykład skonfigurowania parametrów pod kątem progu i minimalnego pola powierzchni:"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "08e79f26",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1500x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"params = cv.SimpleBlobDetector_Params()\n",
"params.minThreshold = 200\n",
"params.maxThreshold = 255\n",
"params.filterByArea = True\n",
"params.minArea = 2000\n",
"\n",
"blob_detector = cv.SimpleBlobDetector_create(params)\n",
"\n",
"keypoints = blob_detector.detect(blobs_gray)\n",
"\n",
"blobs_color = cv.cvtColor(blobs_gray, cv.COLOR_GRAY2BGR)\n",
" \n",
"for kp in keypoints:\n",
" x, y = kp.pt\n",
" x = int(round(x))\n",
" y = int(round(y))\n",
"\n",
" radius = int(round(kp.size/2))\n",
"\n",
" cv.circle(blobs_color, (x,y), radius, (0,0,255), 3)\n",
"\n",
"plt.figure(figsize=[15,5])\n",
"plt.subplot(121)\n",
"plt.imshow(blobs_gray, cmap='gray')\n",
"plt.title(\"Grayscale\")\n",
"plt.subplot(122)\n",
"plt.imshow(blobs_color[:,:,::-1])\n",
"plt.title(\"Blobs\");"
]
},
{
"cell_type": "markdown",
"id": "dc1e0958",
"metadata": {},
"source": [
"### Zadanie 2\n",
"\n",
"Spróbuj wykryć i oznaczyć monety z pliku `img/coins.png`. Przykładowy wynik znajduje się poniżej (użyto schematu kolorów *inferno*, kolejność wykrytych monet nie jest istotna)."
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "5900ec2b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Text(0.5, 1.0, 'Blobs')"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1700x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# miejsce na eksperymenty\n",
"coins = cv.imread(\"img/coins.png\", cv.IMREAD_GRAYSCALE)\n",
"coins_areas = coins.copy()\n",
"coins_blobs = coins.copy()\n",
"\n",
"_, coins_bin = cv.threshold(coins, 180, 255, cv.THRESH_BINARY)\n",
"\n",
"kernel_ellipse = cv.getStructuringElement(cv.MORPH_ELLIPSE, (2, 2))\n",
"\n",
"coins_eroded = cv.morphologyEx(coins_bin, cv.MORPH_OPEN, kernel_ellipse, iterations=5)\n",
"\n",
"coins_contours, coins_hierarchy = cv.findContours(coins_eroded, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)\n",
"coins_with_contours = coins_bin.copy()\n",
"\n",
"#coins_with_contours = cv.cvtColor(coins_with_contours, cv.COLOR_GRAY2BGR)\n",
"\n",
"coins_with_bb = coins_with_contours.copy()\n",
"for contour in coins_contours:\n",
" (x,y), radius = cv.minEnclosingCircle(contour)\n",
" if 30 < radius < 300:\n",
" cv.circle(coins_with_bb, (int(x),int(y)), int(round(radius)), (0,0,0), -1)\n",
"\n",
"params = cv.SimpleBlobDetector_Params()\n",
"params.minThreshold = 0\n",
"params.maxThreshold = 255\n",
"params.filterByArea = True\n",
"params.minArea = 50\n",
"params.maxArea = 1000000\n",
"# params.minDistBetweenBlobs = 100\n",
"#params.filterByCircularity = True\n",
"# params.filterByConvexity = True\n",
"# params.filterByInertia = True\n",
"\n",
"blob_detector = cv.SimpleBlobDetector_create(params)\n",
"\n",
"keypoints = blob_detector.detect(coins_with_bb)\n",
"\n",
"coins_eroded = cv.cvtColor(coins_eroded, cv.COLOR_GRAY2BGR)\n",
"\n",
"for idx, kp in enumerate(keypoints):\n",
" x, y = kp.pt\n",
" x = int(round(x))\n",
" y = int(round(y))\n",
"\n",
" radius = int(round(kp.size/2))\n",
"\n",
" cv.circle(coins_eroded, (x,y), radius, (0,0,255), -1)\n",
"\n",
"\n",
"plt.figure(figsize=[17,5])\n",
"plt.subplot(121)\n",
"plt.imshow(coins_eroded, cmap='inferno')\n",
"plt.title(\"Grayscale\")\n",
"plt.subplot(122)\n",
"plt.imshow(coins_with_bb, cmap=\"gray\")\n",
"plt.title(\"Blobs\")"
]
},
{
"cell_type": "markdown",
"id": "55ce79c1",
"metadata": {},
"source": [
"![Wykryte monety](img/coins_detected.png)"
]
}
],
"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": "02. Operacje binarne na obrazach [laboratoria]",
"title": "Widzenie komputerowe",
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}