s444380-wko/wko-05.ipynb

1347 lines
7.2 MiB
Plaintext
Raw Permalink Normal View History

2023-01-22 20:08:13 +01:00
{
"cells": [
{
"cell_type": "markdown",
"id": "94b34c51",
"metadata": {},
"source": [
"![Logo 1](img/aitech-logotyp-1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Widzenie komputerowe </h1>\n",
"<h2> 05. <i>Transformacje geometryczne i cechy 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": "512b22b6",
"metadata": {},
"source": [
"W poniższych materiałach zobaczymy jak przy pomocy biblitoeki OpenCV realizować transformacje geometryczne obrazu, wyszukiwać \"ciekawe\" elementy obrazu oraz jak łączyć je z innymi podobnymi elementami na innych obrazach.\n",
"\n",
"Na początku załadujmy niezbędne biblioteki."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "4c6170e3",
"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": "2256ace3",
"metadata": {},
"source": [
"# Transformacje obrazu\n",
"\n",
"Zacznijmy od podstawowych przekształceń geometrycznych. Aby efekt poszczególnych operacji był widoczny, dodamy pustą przestrzeń wokół testowego obrazu, na którym będziemy pracować:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "cb9554d1",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 500x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"lena = cv.imread(\"img/lena.png\", cv.IMREAD_COLOR)\n",
"image = np.zeros((1024, 1024, 3), np.uint8)\n",
"\n",
"for i in range(3):\n",
" image[256:768, 256:768, i] = lena[:,:, i];\n",
"\n",
"plt.figure(figsize=(5,5))\n",
"plt.imshow(image[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "3ef7152b",
"metadata": {},
"source": [
"W OpenCV [transformacje afiniczne](https://en.wikipedia.org/wiki/Affine_transformation#Image_transformation) są wykonywane przy pomocy definicji macierzy 2x3 (zamiast bardziej klasycznej 3x3), która przekazywana jest do funkcji [`cv.warpAffine()`](https://docs.opencv.org/4.5.3/da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983). Poniżej mamy przykład translacji (przesunięcia) o 100 pikseli w prawo wzdłuż osi *x* i o 150 pikseli wzdłuż osi *y*:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "29e072c5",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAcoAAAGyCAYAAABk7YRwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9a6xl23XfB/7GmHOtvfd51fNW3Rd5+RJJUdTDkiWZVgwlbVnsNGHAFhEYDXTaENKNjsMYthUYCYFAQQIEMgI0EnRbMYz+YPtDAgVyP9IW1HYrsiUn8ZUpUZYlUyIlkbq8fNx3VZ1T57HXWnOO0R/G3KdISzmtK5EirZo/abNunbNrn73X3meNNcb4j/8Qd3c6nU6n0+n8jujX+gl0Op1Op/P1TA+UnU6n0+lcQQ+UnU6n0+lcQQ+UnU6n0+lcQQ+UnU6n0+lcQQ+UnU6n0+lcQQ+UnU6n0+lcQQ+UnU6n0+lcQQ+UnU6n0+lcQQ+UnU6n0+lcwdd1oPzRH/1R3va2t7Fer/nu7/5uPvaxj32tn1Kn0+l0HjO+bgPlf/ff/Xf80A/9EP/Jf/Kf8Iu/+It867d+Kx/84Ad59dVXv9ZPrdPpdDqPEfL1aor+3d/93Xznd34nf/2v/3UAzIy3vOUt/MW/+Bf5j/6j/+hr/Ow6nU6n87iQv9ZP4Hdinmc+/vGP89GPfvTya6rK933f9/H888//jv9mmiamabr8u5lx7949bt26hYh81Z9zp9PpdL5+cHcePnzI008/jervr3j6dRkoX3/9dWqt3L1798u+fvfuXT75yU/+jv/mR37kR/hP/9P/9A/i6XU6nU7nXxE+97nP8eyzz/6+HuPrtkf5ZvnoRz/K8fHx5e3FF1/8Wj+lTqfT6XyNOTw8/H0/xtdlRnn79m1SSrzyyitf9vVXXnmFJ5988nf8N6vVitVq9Qfx9DqdTqfzrwhfidbb12VGOY4j3/Ed38FP//RPX37NzPjpn/5pPvCBD3wNn1mn0+l0Hje+LjNKgB/6oR/iz//5P88f/aN/lO/6ru/iv/qv/ivOzs74wR/8wa/1U+t0Op3OY8TXbaD8c3/uz/Haa6/xwz/8w7z88st827d9G3//7//93ybw6XQ6nU7nq8nX7Rzl75eTkxOuXbv2tX4anU6n0/kacnx8zNHR0e/rMb4ue5SdTqfT6Xy90ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX0ANlp9PpdDpX8BUPlD/yIz/Cd37nd3J4eMidO3f4M3/mz/CpT33qy+6z3W75yEc+wq1btzg4OODDH/4wr7zyypfd58UXX+RDH/oQe3t73Llzh7/6V/8qpZSv9NPtdDqdTudKvuKB8md/9mf5yEc+ws/93M/xUz/1UyzLwvd///dzdnZ2eZ+/8lf+Cn/v7/09fvzHf5yf/dmf5Ytf/CI/8AM/cPn9Wisf+tCHmOeZf/JP/gl/5+/8Hf723/7b/PAP//BX+ul2Op1Op3M1/lXm1VdfdcB/9md/1t3dHzx44MMw+I//+I9f3ufXfu3XHPDnn3/e3d1/8id/0lXVX3755cv7/I2/8Tf86OjIp2n6Xf3c4+NjB/qt3/qt3/rtMb4dHx//vuPYV71HeXx8DMDNmzcB+PjHP86yLHzf933f5X3e+9738ta3vpXnn38egOeff55v/uZv5u7du5f3+eAHP8jJyQmf+MQnvtpPudPpdDqdS/JX88HNjL/8l/8y3/M938P73/9+AF5++WXGceT69etfdt+7d+/y8ssvX97nS4Pk7vu77/1OTNPENE2Xfz85OflKvYxOp9PpPMZ8VTPKj3zkI/yLf/Ev+LEf+7Gv5o8BQkR07dq1y9tb3vKWr/rP7HQ6nc4ffr5qgfLf//f/fX7iJ36Cf/SP/hHPPvvs5deffPJJ5nnmwYMHX3b/V155hSeffPLyPv+yCnb39919/mU++tGPcnx8fHn73Oc+9xV8NZ1Op9N5bPl9dzn/JczMP/KRj/jTTz/tv/7rv/7bvr8T8/zdv/t3L7/2yU9+0uG3i3leeeWVy/v8zb/5N/3o6Mi32+3v6nl0MU+/9Vu/9Vu/fSXEPF/xQPkX/sJf8GvXrvnP/MzP+EsvvXR5Oz8/v7zPv/vv/rv+1re+1f/hP/yH/gu/8Av+gQ98wD/wgQ9cfr+U4u9///v9+7//+/2XfumX/O///b/vTzzxhH/0ox/9XT+PHij7rd/6rd/67esyUP4vPdm/9bf+1uV9Li4u/N/79/49v3Hjhu/t7fmf/bN/1l966aUve5wXXnjB/81/89/0zWbjt2/f9v/gP/gPfFmW3/Xz6IGy3/qt3/qt374SgVJacPtDx8nJCdeuXftaP41Op9PpfA05Pj7m6Ojo9/UY3eu10+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r6IGy0+l0Op0r+KoHyr/21/4aIsJf/st/+fJr2+2Wj3zkI9y6dYuDgwM+/OEP88orr3zZv3vxxRf50Ic+xN7eHnfu3OGv/tW/Sinlq/10O51Op9P5Mr6qgfLnf/7n+Zt/82/yLd/yLV/29b/yV/4Kf+/v/T1+/Md/nJ/92Z/li1/8Ij/wAz9w+f1aKx/60IeY55l/8k/+CX/n7/wd/vbf/tv88A//8Ffz6XY
"text/plain": [
"<Figure size 500x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mat = np.float32([\n",
" [1.0, 0.0, 100],\n",
" [0.0, 1.0, 150]\n",
"])\n",
"\n",
"image_translated = cv.warpAffine(image, mat, image.shape[0:2])\n",
"\n",
"plt.figure(figsize=(5,5))\n",
"plt.imshow(image_translated[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "c4df87c1",
"metadata": {},
"source": [
"Zobaczmy co się stanie po przeskalowaniu dwukrotnym wzdłuż osi *x*:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "6c71222d",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 500x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mat = np.float32([\n",
" [2.0, 0.0, 0],\n",
" [0.0, 1.0, 0]\n",
"])\n",
"\n",
"image_scaled = cv.warpAffine(image, mat, image.shape[0:2])\n",
"\n",
"plt.figure(figsize=(5,5))\n",
"plt.imshow(image_scaled[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "2bdb4a28",
"metadata": {},
"source": [
"Nasz wyjściowy obraz \"wyszedł\" poza wymiary wejściowe, więc musimy podać w funkcji trochę większe rozmiary wynikowego obrazu (w tym wypadku chodzi o szerokość):"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "b1b3f06e",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mat = np.float32([\n",
" [2.0, 0.0, 0],\n",
" [0.0, 1.0, 0]\n",
"])\n",
"\n",
"image_scaled = cv.warpAffine(image, mat, (2*image.shape[1], image.shape[0]))\n",
"\n",
"plt.figure(figsize=(10,10))\n",
"plt.imshow(image_scaled[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "f23fb260",
"metadata": {},
"source": [
"Poniżej mamy dwukrotne przeskalowanie w obu kierunkach (efekt jest zasadniczo widoczny patrząc na wynikowe skale obu osi):"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "bfcf3049",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 500x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mat = np.float32([\n",
" [2.0, 0.0, 0],\n",
" [0.0, 2.0, 0]\n",
"])\n",
"\n",
"image_scaled = cv.warpAffine(image, mat, (2*image.shape[1], 2*image.shape[0]))\n",
"\n",
"plt.figure(figsize=(5,5))\n",
"plt.imshow(image_scaled[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "19370776",
"metadata": {},
"source": [
"W przypadku obrotu musimy pamiętać, że mamy inaczej zdefiniowany układ współrzędnych (oś *y*), więc uzyskujemy trochę inną formę macierzy obrotu:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "b28b1582",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 500x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"angle = 30 * np.pi / 180.0\n",
"\n",
"cos_theta = np.cos(angle)\n",
"sin_theta = np.sin(angle)\n",
"\n",
"mat = np.float32([\n",
" [ cos_theta, sin_theta, 0],\n",
" [-sin_theta, cos_theta, 0]\n",
"])\n",
"\n",
"image_rotated = cv.warpAffine(image, mat, image.shape[0:2])\n",
"\n",
"plt.figure(figsize=(5,5))\n",
"plt.imshow(image_rotated[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "396af8c3",
"metadata": {},
"source": [
"Powyżej mieliśmy obrót wokół środka układu, ale możemy też uzyskać obrót wokół wskazanego punktu, np. środka obrazu:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "d6cca027",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 500x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"angle = 30 * np.pi / 180.0\n",
"\n",
"cos_theta = np.cos(angle)\n",
"sin_theta = np.sin(angle)\n",
"\n",
"center_x = image.shape[0] / 2\n",
"center_y = image.shape[1] / 2\n",
"\n",
"t_x = (1 - cos_theta) * center_x - sin_theta * center_y\n",
"t_y = sin_theta * center_x + (1 - cos_theta) * center_y\n",
"\n",
"mat = np.float32([\n",
" [ cos_theta, sin_theta, t_x],\n",
" [-sin_theta, cos_theta, t_y]\n",
"])\n",
"\n",
"image_rotated = cv.warpAffine(image, mat, image.shape[0:2])\n",
"\n",
"plt.figure(figsize=(5,5))\n",
"plt.imshow(image_rotated[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "5501dcac",
"metadata": {},
"source": [
"Na szczęście zamiast samodzielnego liczenia macierzy obrotu można użyć funkcji [`cv.getRotationMatrix2D()`](https://docs.opencv.org/4.5.3/da/d54/group__imgproc__transform.html#gafbbc470ce83812914a70abfb604f4326) (możemy też jej użyć do skalowania):"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "8b1f159c",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 500x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mat = cv.getRotationMatrix2D((center_x, center_y), 30, 1)\n",
"\n",
"image_rotated = cv.warpAffine(image, mat, image.shape[0:2])\n",
"\n",
"plt.figure(figsize=(5,5))\n",
"plt.imshow(image_rotated[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "0152bb4c",
"metadata": {},
"source": [
"Poniżej mamy przykład pochylenia:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "7ebb76e4",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 500x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mat = np.float32([\n",
" [1.0, 0.1, 0],\n",
" [0.0, 1.0, 0]\n",
"])\n",
"\n",
"image_sheared = cv.warpAffine(image, mat, image.shape[0:2])\n",
"\n",
"plt.figure(figsize=(5,5))\n",
"plt.imshow(image_sheared[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "a101e5a6",
"metadata": {},
"source": [
"Jeżeli mamy kilka transformacji do wykonania, to bardziej efektywnym rozwiązaniem będzie uprzednie wymnożenie macierzy odpowiedzialnych za poszczególne transformacje (zamiast sukcesywnego wykonywania pojedynczych, izolowanych operacji):"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "c914ddfd",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 500x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"m_scale = np.float32([\n",
" [0.5, 0.0],\n",
" [0.0, 1.0]\n",
"])\n",
"\n",
"m_shear = np.float32([\n",
" [1.0, 0.1],\n",
" [0.0, 1.0]\n",
"])\n",
"\n",
"m_rotation = np.float32([\n",
" [ cos_theta, sin_theta],\n",
" [-sin_theta, cos_theta]\n",
"])\n",
"\n",
"v_translation = np.float32([\n",
" [150],\n",
" [90]\n",
"])\n",
"\n",
"mat_tmp = m_rotation @ m_shear @ m_scale\n",
"\n",
"mat_transformation = np.append(mat_tmp, v_translation, 1)\n",
"\n",
"image_transformed = cv.warpAffine(image, mat_transformation, image.shape[0:2])\n",
"\n",
"plt.figure(figsize=(5,5))\n",
"plt.imshow(image_transformed[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "68f6d1d0",
"metadata": {},
"source": [
"Dla punktów o konkretnych współrzędnych możemy też obliczyć ich docelowe współrzędne po transformacjach:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "753b1779",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[200.98076 118.30127]\n",
" [317.71466 280.6903 ]\n",
" [287.15027 68.55127]\n",
" [403.88422 230.94032]]\n"
]
}
],
"source": [
"src_points = np.float32([[50, 50], [50, 249], [249, 50], [249, 249]])\n",
"dst_points = (mat_tmp @ src_points.T + v_translation).T\n",
"\n",
"print(dst_points)"
]
},
{
"cell_type": "markdown",
"id": "12fe63be",
"metadata": {},
"source": [
"Mając co najmniej 3 punkty wejściowe i ich odpowiedniki wyjściowe, możemy oszacować macierz transformacji przy pomocy funkcji [`cv.estimateAffine2D()`](https://docs.opencv.org/4.5.3/d9/d0c/group__calib3d.html#ga27865b1d26bac9ce91efaee83e94d4dd):"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "244b0a24",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Explicit matrix:\n",
"\n",
" [[ 0.4330127 0.58660257 150. ]\n",
" [ -0.25 0.8160254 90. ]]\n",
"\n",
"Estimated matrix:\n",
"\n",
" [[ 0.43301261 0.58660252 150.00000192]\n",
" [ -0.25 0.81602532 90.00000368]]\n"
]
}
],
"source": [
"mat_estimated_1 = cv.estimateAffine2D(src_points[:3], dst_points[:3])[0]\n",
"print(\"Explicit matrix:\\n\\n\", mat_transformation)\n",
"print(\"\\nEstimated matrix:\\n\\n\", mat_estimated_1)"
]
},
{
"cell_type": "markdown",
"id": "967d8ae3",
"metadata": {},
"source": [
"Mając więcej punktów możemy spróbować uzyskać dokładniejsze oszacowanie:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "53e14d49",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Explicit matrix:\n",
"\n",
" [[ 0.4330127 0.58660257 150. ]\n",
" [ -0.25 0.8160254 90. ]]\n",
"\n",
"Estimated matrix:\n",
"\n",
" [[ 0.43301273 0.58660264 149.99997897]\n",
" [ -0.24999996 0.81602536 89.99999603]]\n"
]
}
],
"source": [
"mat_estimated_2 = cv.estimateAffine2D(src_points, dst_points)[0]\n",
"print(\"Explicit matrix:\\n\\n\", mat_transformation)\n",
"print(\"\\nEstimated matrix:\\n\\n\", mat_estimated_2)"
]
},
{
"cell_type": "markdown",
"id": "494b3706",
"metadata": {},
"source": [
"Załóżmy, że chcielibyśmy teraz uzyskać zmianę perspektywy, co w efekcie spowodowałoby, że nasz kwadratowy obraz zamieniłby się w trapez:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "b98c1e5b",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x1000 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"image_to_transform = np.zeros(image.shape, dtype=np.float32)\n",
"dst_points = np.float32([[356, 256], [667, 256], [767, 767], [256, 767]])\n",
"cv.fillConvexPoly(image_to_transform, np.int32(dst_points), (0.8, 0.8, 0.5), cv.LINE_AA);\n",
"\n",
"plt.figure(figsize=[10,10])\n",
"plt.subplot(121)\n",
"plt.imshow(image[:,:,::-1])\n",
"plt.title('Original image')\n",
"\n",
"plt.subplot(122)\n",
"plt.imshow(image_to_transform[:,:,::-1])\n",
"plt.title('Destination plane');"
]
},
{
"cell_type": "markdown",
"id": "2313e3f4",
"metadata": {},
"source": [
"Niestety przy pomocy transformacji afinicznych [nie jesteśmy w stanie](https://stackoverflow.com/a/45644845) uzyskać zakładanego efektu:"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "f68a6095",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABNUAAAGXCAYAAACUfmbSAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdeaCcVX34//c553lm7pLkZk9kC2GRRaJoEEVEcEFqoVoXXKGC2oIbYqu1+FW02opLW/XnglYtKNLWQrV1RbEsdcGqKIoIqMgOCWS968zzPOd8fn98zgxcEiAXEhLw87KjzWTunWfm3jxnns/5LE5EBGOMMcYYY4wxxhhjzBbz2/sAjDHGGGOMMcYYY4x5uLGgmjHGGGOMMcYYY4wxM2RBNWOMMcYYY4wxxhhjZsiCasYYY4wxxhhjjDHGzJAF1YwxxhhjjDHGGGOMmSELqhljjDHGGGOMMcYYM0MWVDPGGGOMMcYYY4wxZoYsqGaMMcYYY4wxxhhjzAxZUM0YY4wxxhhjjDHGmBmyoJr5g/Dud78b59wD+tqzzz4b5xw33HDD1j2ou7nhhhtwznH22Wff5+MuueQSnHNccskl2+xYjDHGbF3OOd797ndvl+d+OKwbD4djNMaYzfnJT37CU57yFIaHh3HOccUVV2zvQ9oqtvT658FcYz3cvO51r+PII498QF87Pj7Oa17zGpYuXYpzjlNPPRWA1atX86IXvYgFCxbgnOMjH/nIQ7Im1nXNrrvuyic/+clt9hx/SCyoZnZoV111Fccddxw777wz7XabnXbaiVe84hVcddVV2/vQjDHG7EB6FwC928DAADvttBNHHXUU/9//9/8xNja2TZ//m9/85nYLnAF88pOfvN+NGWOM2VHd/fx9X7cdKfhe1zXHHnss69at48Mf/jDnnHMOy5Yt296HZbaB66+/ns9+9rO8/e1vf0Bf/773vY+zzz6b1772tZxzzjkcf/zxALz5zW/m29/+NqeddhrnnHMOf/RHf7Q1D/telWXJX/7lX/L3f//3dDqdh+Q5H8mciMj2PghjNufLX/4yL3vZy5g/fz6vfvWrWb58OTfccAOf+9znWLt2Lf/+7//O85///C36Xk3T0DQNAwMDMz6OGCN1XdNut7fZTswNN9zA8uXLOeusszjhhBPu9XEpJaqqotVq4b3FxI0xpufss8/mxBNP5D3veQ/Lly+nrmtWrVrFJZdcwoUXXshuu+3GV7/6VR772Mduk+d/wxvewCc+8Qk297Gq0+lQFAVFUWyT5wY44IADWLhw4SYXnA+HdeOSSy7h6U9/OhdffDFHHHHE9j4cY8x28MUvfnHan7/whS9w4YUXcs4550y7/8gjj2TJkiUP5aHdq2uuuYb99tuPz3zmM7zmNa/Z3oezVfXW1Ouvv57dd9/9Xh/3YK6xHk5OPfVUvvWtb3Httdc+oK9/8pOfTFEUfP/73592/9KlS3nWs5417ff/oVq3N2zYwJIlSzjzzDN51atetc2e5w/Btvt0Z8yDcN1113H88cezxx578L//+78sWrSo/3dvetObOOywwzj++OP55S9/yR577HGv32diYoLh4eEHdTETQiCE8IC+dmvz3j/iFy1jjHkwnvOc53DQQQf1/3zaaadx0UUXccwxx/Dc5z6Xq6++msHBwYf0mLbnedvWDWPMw8Fxxx037c8/+tGPuPDCCze5/54mJycZGhralod2r+644w4A5s6du9W+Z+/a5eFiW28Y7Qjquubcc8/l5JNPfsDf44477mD//fff7P33/P15qNbtuXPn8uxnP5uzzz7bgmoP0o65ZWn+4H3oQx9icnKSf/7nf54WUANYuHAhn/70p5mYmOCDH/xg//5eTf+vf/1rXv7ylzNv3jye+tSnTvu7u5uamuKUU05h4cKFzJ49m+c+97nceuutm/S+2VxPgd13351jjjmG73//+xx88MEMDAywxx578IUvfGHac6xbt463vOUtrFixglmzZjFnzhye85zn8Itf/OIBvS+bq7E/4ogjOOCAA/jlL3/J4YcfztDQEHvttRfnn38+AJdeeilPetKTGBwcZJ999uG73/3utO9544038rrXvY599tmHwcFBFixYwLHHHrvZHgq95xgcHGSXXXbh7/7u7zjrrLM223PhW9/6FocddhjDw8PMnj2bo48+2sp2jTHbxTOe8Qze+c53cuONN26SDXHNNdfwohe9iPnz5zMwMMBBBx3EV7/61WmPqeuav/3bv2XvvfdmYGCABQsW8NSnPpULL7wQgBNOOIFPfOITwPQSpp57riu9Nel3v/sdJ5xwAnPnzmVkZIQTTzyRycnJac991lln8YxnPIPFixfTbrfZf//9OfPMM6c9Zvfdd+eqq67i0ksv7T93L+Pr3nqznHfeeaxcuZLBwUEWLlzIcccdx6233jrtMSeccAKzZs3i1ltv5U//9E+ZNWsWixYt4i1veQsxxvt933tr5Xe+8x0OPPBABgYG2H///fnyl798v1/7ve99j2OPPZbddtuNdrvNrrvuypvf/GampqYe8DGmlPjIRz7CYx7zGAYGBliyZAknnXQS69evv9/jMcZsf73PvJdffjlPe9rTGBoa6pfj/fd//zdHH300O+20E+12mz333JP3vve9m5wHet/j17/+NU9/+tMZGhpi5513nnZN0fOxj32MxzzmMQwNDTFv3jwOOugg/vVf/xXQc8/hhx8OwLHHHjvtvAtw0UUX9T8Hz507l+c973lcffXV077/fV279M6fl1xyCQcddBCDg4OsWLGify7/8pe/zIoVKxgYGGDlypX8/Oc/3+T4t2R9A22384xnPGPa5/uU0hb9TDZ3jeWc4w1veAPnnXce+++/P4ODgxxyyCFceeWVAHz6059mr732YmBggCOOOGKTa4gtPf8D/ecYGBjggAMO4Ctf+QonnHDCJtl1D+b8//3vf581a9bwrGc9a9r9VVVx+umns3LlSkZGRhgeHuawww7j4osv7j+mtwZff/31fOMb3+iv0b3rSxHhE5/4xLTPDfd1vbclv7fdbpd3vetd7LXXXv3376//+q/pdrubPPbII4/k+9//PuvWrbvf98Hcu0d2WNk8bH3ta19j991357DDDtvs3z/taU9j99135xvf+MYmf3fsscey99578773vW+zZTg9J5xwAv/xH//B8ccfz5Of/GQuvfRSjj766C0+xt/97ne86EUv4tWvfjWvfOUr+Zd/+RdOOOEEVq5cyWMe8xgAfv/73/Nf//VfHHvssSxfvpzVq1fz6U9/msMPP5xf//rX7LTTTlv8fPdl/fr1HHPMMbz0pS/l2GOP5cwzz+SlL30p5557Lqeeeionn3wyL3/5y/nQhz7Ei170Im6++WZmz54NaIPVH/7wh7z0pS9ll1124YYbbuDMM8/kiCOO4Ne//nV/9+/WW2/l6U9/Os45TjvtNIaHh/nsZz9Lu93e5HjOOeccXvnKV3LUUUfxgQ98gMnJSc4880ye+tSn8vOf//w+08iNMWZbOP7443n729/Od77zHf78z/8c0AuJQw89lJ133pm/+Zu/YXh4mP/4j//gT//0T/nP//zPfouBd7/73Zxxxhm85jWv4eCDD2Z0dJSf/vSn/OxnP+PII4/kpJNO4rbbbttsqdJ9efGLX8zy5cs544wz+NnPfsZnP/tZFi9ezAc+8IH+Y84880we85jH8NznPpeiKPja177G6173OlJKvP71rwfgIx/5CG984xuZNWsW/+///T+A+yyP6pX1PPGJT+SMM85g9erVfPSjH+UHP/gBP//5z6ftmscYOeqoo3jSk57EP/zDP/Dd736Xf/zHf2TPPffkta997f2+xt/+9re85CUv4eSTT+aVr3wlZ511FsceeywXXHDBfTZ8Pu+885icnOS1r30tCxYs4Mc//jEf+9jHuOWWWzjvvPOmPXZLj/Gkk07qv/ZTTjmF66+/no9//OP8/Oc/5wc/+AFlWd7v6zHGbF9r167lOc95Di996Us57rjj+ue6s88+m1mzZvGXf/mXzJo1i4suuojTTz+d0dFRPvShD03
"text/plain": [
"<Figure size 1500x1000 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"src_points = np.float32([[256, 256], [767, 256], [767, 767], [256, 767]])\n",
"mat_estimated = cv.estimateAffine2D(src_points, dst_points)[0]\n",
"\n",
"image_transformed_a = cv.warpAffine(image, mat_estimated, image.shape[0:2])\n",
"\n",
"plt.figure(figsize=[15,10])\n",
"plt.subplot(131)\n",
"plt.imshow(image[:,:,::-1])\n",
"plt.title('Original image')\n",
"plt.subplot(132)\n",
"plt.imshow(image_to_transform[:,:,::-1])\n",
"plt.title('Destination plane')\n",
"plt.subplot(133)\n",
"plt.imshow(image_transformed_a[:,:,::-1])\n",
"plt.title('Transformed image (affine)');"
]
},
{
"cell_type": "markdown",
"id": "66864db4",
"metadata": {},
"source": [
"Do uzyskania zakładanego efektu musimy znaleźć macierz [homografii](https://en.wikipedia.org/wiki/Homography) 3x3 przy pomocy co najmniej 4 punktów i funkcji [`cv.findHomography()`](https://docs.opencv.org/4.5.3/d9/d0c/group__calib3d.html#ga4abc2ece9fab9398f2e560d53c8c9780):"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "62324a22",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 5.08838663e-01 -3.27547619e-01 2.51229024e+02]\n",
" [ 0.00000000e+00 3.44904761e-01 1.25737302e+02]\n",
" [ 0.00000000e+00 -6.40366802e-04 1.00000000e+00]]\n"
]
}
],
"source": [
"mat_h = cv.findHomography(src_points, dst_points)[0]\n",
"print(mat_h)"
]
},
{
"cell_type": "markdown",
"id": "df477c3a",
"metadata": {},
"source": [
"Przy pomocy funkcji [`cv.warpPerspective()`](https://docs.opencv.org/4.5.3/da/d54/group__imgproc__transform.html#gaf73673a7e8e18ec6963e3774e6a94b87) możemy dokonać teraz zmiany perspektywy:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "6f804489",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABlgAAAGTCAYAAABEeB+0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdeZycRbX4/09VPU/3bJnJnpAASVgEAigYRAOyg1yEiyubAoKooCziLl4voN4LoleFHyigeNnEDVy+riheBDfcQBBBViFAIHsyySzd/TxV9fvjVDcZEiCTDEyi5/16tZKenunqzuSprjp1zjExxohSSimllFJKKaWUUkoppZRaZ3a0B6CUUkoppZRSSimllFJKKbWp0QCLUkoppZRSSimllFJKKaXUMGmARSmllFJKKaWUUkoppZRSapg0wKKUUkoppZRSSimllFJKKTVMGmBRSimllFJKKaWUUkoppZQaJg2wKKWUUkoppZRSSimllFJKDZMGWJRSSimllFJKKaWUUkoppYZJAyxKKaWUUkoppZRSSimllFLDpAEWpZRSSimllFJKKaWUUkqpYdIAi/qnde6552KMWa/vveqqqzDG8Oijj47soFbz6KOPYozhqquues7H3XLLLRhjuOWWW16wsSillFo/xhjOPffcUXnuTWF+2BTGqJRSf/rTn9hjjz3o7OzEGMOdd9452kMaEeu6ptmQddOm5j3veQ8HHXTQen1vX18f73jHO5g6dSrGGM4880wAFi5cyJvf/GYmTJiAMYYLL7zwRZn/iqJgiy224Etf+tIL9hxKbcr02v6ve21vXoNvuOGGURzVP5cX4j191atexYc//OER+3mjSQMsaqNzzz33cOyxxzJ9+nSq1SrTpk3jrW99K/fcc89oD00ppdQoaC4imre2tjamTZvGwQcfzP/3//1/rFq16gV9/p/85CejFkQB+NKXvvS8wXillNoYrH6tfq7bxhR0LYqCI444gmXLlvGFL3yBa6+9lhkzZoz2sNQL4JFHHuGKK67gYx/72Hp9/3nnncdVV13Fu9/9bq699lqOO+44AN73vvfxs5/9jLPOOotrr72Wf/u3fxvJYT+rPM95//vfz3//939Tq9VelOdU/5r02q42Zht6bVej5yMf+Qhf/OIXWbBgwWgPZYNloz0ApVb33e9+l2OOOYbx48dz0kknMWvWLB599FG++tWvcsMNN/DNb36TN7zhDev0sz7+8Y/z0Y9+dL3Gcdxxx3H00UdTrVbX6/tH0t57783g4CCVSmW0h6KUUqPqk5/8JLNmzaIoChYsWMAtt9zCmWeeyec//3l+8IMf8NKXvvQFed6f/OQnfPGLX1xrkGVwcJAse2E/Tn3pS19i4sSJnHDCCUPu1/lBKbWxufbaa4f8+ZprruGmm25a4/4ddtjhxRzWc3r44YeZN28eX/nKV3jHO94x2sMZFRuybtqUXHTRRcyaNYv99ttvvb7/5ptv5lWvehXnnHPOGve/7nWv44Mf/GDrvpe85CUvyhx94okn8tGPfpSvf/3rvP3tb39Bn0v969Jr+6ZJr+1qY/e6172O7u5uvvSlL/HJT35ytIezQTTAojYaDz/8MMcddxxbbbUVv/rVr5g0aVLra+9973vZa6+9OO644/jrX//KVltt9aw/p7+/n87OTrIsW+9NL+cczrn1+t6RZq2lra1ttIehlFKj7pBDDmG33XZr/fmss87i5ptv5rDDDuPwww/n73//O+3t7S/qmEbz+qzzg1JqY3PssccO+fPvf/97brrppjXuf6aBgQE6OjpeyKE9q0WLFgEwduzYEfuZzfXIpmJD1k2biqIouO666zjllFPW+2csWrSI2bNnr/X+Z/7+vFhz9NixY3nNa17DVVddpQEW9YLRa7vQa/vGZySu7f9sRvPf3XBZa3nzm9/MNddcwyc+8YlNuqSdlghTG43PfvazDAwM8OUvf3lIcAVg4sSJXH755fT39/OZz3ymdX+zpuS9997LW97yFsaNG8erX/3qIV9b3eDgIGeccQYTJ05kzJgxHH744cyfP3+NGvprq2k5c+ZMDjvsMH7zm9+w++6709bWxlZbbcU111wz5DmWLVvGBz/4QXbeeWe6urro7u7mkEMO4a677lqv92Vt9Xv33XdfdtppJ/7617+yzz770NHRwTbbbNOqhXjrrbfyyle+kvb2drbbbjt+8YtfDPmZ8+bN4z3veQ/bbbcd7e3tTJgwgSOOOGKtNTybz9He3s7mm2/Of/3Xf3HllVeutebnT3/6U/baay86OzsZM2YMhx56qJZ2U0q9oPbff3/+8z//k3nz5vG1r31tyNfuu+8+3vzmNzN+/Hja2trYbbfd+MEPfjDkMUVR8IlPfIJtt92WtrY2JkyYwKtf/WpuuukmAE444QS++MUvAkPLIzQ9c/5ozj0PPfQQJ5xwAmPHjqWnp4cTTzyRgYGBIc995ZVXsv/++zN58mSq1SqzZ8/m0ksvHfKYmTNncs8993Drrbe2nnvfffcFnr2/yfXXX8+cOXNob29n4sSJHHvsscyfP3/IY0444QS6urqYP38+r3/96+nq6mLSpEl88IMfxHv/vO97c078+c9/zi677EJbWxuzZ8/mu9/97vN+769//WuOOOIIttxyS6rVKltssQXve9/7GBwcXO8xhhC48MIL2XHHHWlra2PKlCmcfPLJLF++/HnHo5R6cTU/x95+++3svffedHR0tMp6/L//9/849NBDmTZtGtVqla233ppPfepTa/ybb/6Me++9l/3224+Ojg6mT58+ZJ3QdPHFF7PjjjvS0dHBuHHj2G233fj6178OyHVmn332AeCII44Yco0FyUxofrYdO3Ysr3vd6/j73/8+5Oc/13qkea285ZZb2G233Whvb2fnnXduXbe/+93vsvPOO9PW1sacOXP4y1/+ssb412UuAymzvP/++w/5zB5CWKe/k7Wtm4wxnHbaaVx//fXMnj2b9vZ25s6dy9133w3A5ZdfzjbbbENbWxv77rvvGuuCdb3WA63naGtrY6edduJ73/seJ5xwAjNnzhzyuA251v/mN79hyZIlHHjggUPubzQanH322cyZM4eenh46OzvZa6+9+OUvf9l6THO+feSRR/jxj3/cmo+ba8YYI1/84heHfEZ4rjXcuvze1ut1zjnnHLbZZpvW+/fhD3+Yer2+xmMPOuggfvOb37Bs2bLnfR+UeqHotV2v7c80mtf21X/2f//3f7P55pvT1tbGAQccwEMPPbTWsa7r+umxxx7jsMMOo6uri+nTp7fWinfffTf7778/nZ2dzJgxo/X7uLp//OMfHHHEEYwfP56Ojg5e9apX8eMf/3iNx82bN4/DDz+czs5OJk+e3CpF+Wzzykj8u7v99tvZY489aG9vZ9asWVx22WXr9Z6ec8455HnO4sWL1/jed73rXYwdO3ZIWcuDDjqIefPmbfI9kv65Q5lqk/LDH/6QmTNnstdee63163vvvTczZ85c68XniCOOYNttt+W8884jxvisz3HCCSfw7W9/m+OOO45XvepV3HrrrRx66KHrPMaHHnqIN7/5zZx00km87W1v43//93854YQTmDNnDjvuuCMgF8zvf//7HHHEEcyaNYuFCxdy+eWXs88++3Dvvfcybdq0dX6+57J8+XIOO+wwjj76aI444gguvfRSjj76aK677jrOPPNMTjnlFN7ylrfw2c9+lje/+c08/vjjjBkzBpBmb7/73e84+uij2XzzzXn00Ue59NJL2Xfffbn33ntb0e758+ez3377YYzhrLPOorOzkyuuuGKtpdOuvfZa3va2t3HwwQdzwQUXMDAwwKWXXsqrX/1q/vKXv6wxiSql1Eg57rjj+NjHPsbPf/5z3vnOdwKyGNlzzz2ZPn06H/3oR+ns7OTb3/42r3/96/nOd77TKjd57rnncv755/OOd7yD3XffnZUrV/LnP/+ZO+64g4MOOoiTTz6ZJ598cq1lEJ7LkUceyaxZszj//PO54447uOKKK5g8eTIXXHBB6zGXXnopO+64I4cffjhZlvHDH/6Q97znPYQQOPX
"text/plain": [
"<Figure size 2000x1000 with 4 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"image_transformed_h = cv.warpPerspective(image, mat_h, image.shape[0:2])\n",
"\n",
"plt.figure(figsize=[20,10])\n",
"plt.subplot(141)\n",
"plt.imshow(image[:,:,::-1])\n",
"plt.title('Original image')\n",
"plt.subplot(142)\n",
"plt.imshow(image_to_transform[:,:,::-1])\n",
"plt.title('Destination plane')\n",
"plt.subplot(143)\n",
"plt.imshow(image_transformed_a[:,:,::-1])\n",
"plt.title('Transformed image (affine)')\n",
"plt.subplot(144)\n",
"plt.imshow(image_transformed_h[:,:,::-1])\n",
"plt.title('Transformed image (homography)');"
]
},
{
"cell_type": "markdown",
"id": "5e60a8e1",
"metadata": {},
"source": [
"Poprzez znalezienie macierzy homografii i zmianę perspektywy możemy np. wyrównywać zdjęcia dokumentów w celu ich dalszej analizy. Poniżej mamy przykład z oznaczeniem okładki zeszytu:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "1d02f81a",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x1000 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"book = cv.imread(\"img/caribou.jpg\", cv.IMREAD_COLOR)\n",
"image_h, image_w = book.shape[0:2]\n",
"\n",
"src_points = np.array([[210, 190], [380, 280], [290, 500], [85, 390]], dtype=float)\n",
"dst_points = np.array([[0, 0],[image_w-1, 0], [image_w-1, image_h-1], [0, image_h-1]], dtype=float)\n",
"\n",
"colors = [(0,0,255), (0,255,0), (255,0,0), (90,200,200)]\n",
"for (x,y), i in(zip(src_points, colors)):\n",
" book = cv.circle(book, (int(x),int(y)), 10, i, -1)\n",
"\n",
"mat = cv.findHomography(src_points, dst_points)[0]\n",
"\n",
"book_aligned = cv.warpPerspective(book, mat, (image_w, image_h))\n",
"\n",
"plt.figure(figsize=[10,10])\n",
"plt.subplot(121)\n",
"plt.imshow(book[:,:,::-1])\n",
"plt.title('Original image')\n",
"plt.subplot(122)\n",
"plt.imshow(book_aligned[:,:,::-1])\n",
"plt.title('Aligned image');"
]
},
{
"cell_type": "markdown",
"id": "062ebf74",
"metadata": {},
"source": [
"W przypadku dokumentów, możemy np. dysponować wzorem dokumentu do uzupełnienia oraz zdjęciem wypełnionego dokumentu. Po wyrówaniu zdjęcia moglibyśmy łatwiej analizować wypełnione pola:\n",
"\n",
"![Przykładowe wyrówanie dokumentu. Źródło: learnopencv.org](img/document-alignment.png)\n",
"\n",
"Cztery niezbędne punkty moglibyśmy wybierać ręcznie, jednak w przypadku masowego przetwarzania lepszym rozwiązaniem jest automatyczne znalezienie odpowiadających sobie punktów (niekoniecznie rogów dokumentu) na wzorcu i przetwarzanym zdjęciu. Poniżej zobaczymy jak można znaleźć i dopasować takie punkty."
]
},
{
"cell_type": "markdown",
"id": "c1692205",
"metadata": {},
"source": [
"# Punkty kluczowe\n",
"\n",
"Punkty kluczowe (ang. *keypoints*) są punktami na obrazie, o których możemy myśleć w kategoriach dobrze zdefiniowanych narożników, relatywnie odpornych na przekształcenia obrazu. Każdy punkt kluczowy ma przypisany descryptor tj. [wektor cech](https://stackoverflow.com/a/42116946).\n",
"\n",
"Wczytajmy przykładowy obraz, na którym postaramy się znaleźć takie punkty kluczowe:"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "8471d86c",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAz8AAAI5CAYAAACPe4TqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOy9eZwdR3nv/a3q7rPNvmo00oz2zVqsxfsmG2MUsLAB48QEjG24iUlYXl5uQsJNLkngvjg3vLmf5A1LSNgSsCGxwQQwNrYx3ldZkiVrtC+jfRnNPnOW7q56/zhT7T5nZiRZtiVZqu/HY8306aW6uk/96qnnqaeE1lpjsVgsFovFYrFYLGc58nQXwGKxWCwWi8VisVhOBdb4sVgsFovFYrFYLOcE1vixWCwWi8VisVgs5wTW+LFYLBaLxWKxWCznBNb4sVgsFovFYrFYLOcE1vixWCwWi8VisVgs5wTW+LFYLBaLxWKxWCznBNb4sVgsFovFYrFYLOcE1vixWCwWi8VisVgs5wTW+LGclfz1X/81QoiTOvb73/8+Qgh27dr15hYqxq5duxBC8P3vf/+Y+z3++OMIIXj88cffsrJYLBaLxXL77bczderUN+18b0SHLZa3Emv8WM4oNmzYwEc+8hEmTZpEMpmktbWVD3/4w2zYsOF0F81isVgsZyE7d+7kU5/6FLNnzyaTyZDJZDjvvPP45Cc/ybp160538SwWy5uM0Frr010IiwXgpz/9KR/60Ieor6/n4x//ONOmTWPXrl185zvf4ejRo/z4xz/m/e9//wmdKwgCgiAglUq97nKEYYjv+ySTybds1GrXrl1MmzaN733ve9x+++3j7qeUolAokEgkkNKOVVgsFsubyS9/+Ut+7/d+D9d1+fCHP8z555+PlJJNmzbx05/+lM7OTnbu3MmUKVNOd1Hfcm6//XYef/zxNy3q4Y3osMXyVuKe7gJYLADbt2/n1ltvZfr06Tz55JM0NTVFn/1f/9f/xZVXXsmtt97KunXrmD59+rjnGRoaoqKiAtd1cd2Te70dx8FxnJM69s1GSmmFw2KxWN4Ctm/fzi233MKUKVP4zW9+w8SJE0s+/9//+3/zjW9847gDT0Z3LKW8ER22WN5K7FCy5Yzgq1/9KsPDw/zLv/xLieED0NjYyLe+9S2Ghob4u7/7u2i7iSfu6Ojg93//96mrq+OKK64o+SxONpvlM5/5DI2NjVRVVXHDDTewb98+hBD89V//dbTfWHN+pk6dysqVK3n66ae56KKLSKVSTJ8+nX//938vuUZ3dzd/8id/wsKFC6msrKS6upp3v/vdvPLKKydVL2PN+bn66qtZsGAB69atY/ny5WQyGWbOnMl9990HwBNPPMHFF19MOp1mzpw5PProoyXn7Ozs5I//+I+ZM2cO6XSahoYGbr755jFH+8w10uk0kydP5n/9r//F9773vTHnRD344INceeWVVFRUUFVVxfXXX2/DFS0WyxnL3/3d3zE0NMT3vve9UYYPFDvvn/nMZ2hra4u23X777VRWVrJ9+3be8573UFVVxYc//GEAnnrqKW6++Wba29tJJpO0tbXxf//f/zfZbDY63rSfa9asGXW9r3zlKziOw759+wDYunUrN910Ey0tLaRSKSZPnswtt9xCX19fyXE//OEPueiii8hkMtTV1XHVVVfx8MMPR5//13/9F9dffz2tra0kk0lmzJjBl7/8ZcIwPG4dKaX4h3/4B+bPn08qlWLChAnceeed9PT0HPfYsXRYCMGnPvUp7r33Xs477zzS6TSXXnop69evB+Bb3/oWM2fOJJVKcfXVV4/SmROpY4O5RiqVYsGCBdx///1jzmt6I/doeXtiTXLLGcEvfvELpk6dypVXXjnm51dddRVTp07lgQceGPXZzTffzKxZs/jKV77CsaI4b7/9dv7zP/+TW2+9lUsuuYQnnniC66+//oTLuG3bNj74wQ/y8Y9/nNtuu43vfve73H777Sxbtoz58+cDsGPHDn72s59x8803M23aNA4dOsS3vvUtli9fTkdHB62trSd8vWPR09PDypUrueWWW7j55pv55je/yS233MLdd9/NZz/7WT7xiU/w+7//+3z1q1/lgx/8IHv27KGqqgqAl156iWeffZZbbrmFyZMns2vXLr75zW9y9dVX09HRQSaTAWDfvn1cc801CCH4whe+QEVFBd/+9rdJJpOjyvODH/yA2267jRUrVvC///f/Znh4mG9+85tcccUVrFmz5k2dRGuxWCxvBr/85S+ZOXMmF1988es6LggCVqxYwRVXXMH/+//+v1Gbee+99zI8PMwf/dEf0dDQwIsvvsg//dM/sXfvXu69914APvjBD/LJT36Su+++myVLlpSc9+677+bqq69m0qRJFAoFVqxYQT6f59Of/jQtLS3s27ePX/7yl/T29lJTUwPA3/zN3/DXf/3XXHbZZXzpS18ikUjwwgsv8Nhjj/Gud70LKA7oVVZW8rnPfY7Kykoee+wxvvjFL9Lf389Xv/rVY97rnXfeyfe//33uuOMOPvOZz7Bz506+9rWvsWbNGp555hk8z3tddQdFA+bnP/85n/zkJwG46667WLlyJZ///Of5xje+wR//8R/T09PD3/3d3/Gxj32Mxx57LDr2ROoY4IEHHuD3fu/3WLhwIXfddRc9PT18/OMfZ9KkSafkHi1nONpiOc309vZqQN94443H3O+GG27QgO7v79daa/1Xf/VXGtAf+tCHRu1rPjO8/PLLGtCf/exnS/a7/fbbNaD/6q/+Ktr2ve99TwN6586d0bYpU6ZoQD/55JPRtsOHD+tkMqn/+3//79G2XC6nwzAsucbOnTt1MpnUX/rSl0q2Afp73/veMe/5t7/9rQb0b3/722jb8uXLNaDvueeeaNumTZs0oKWU+vnnn4+2//rXvx51neHh4VHXee655zSg//3f/z3a9ulPf1oLIfSaNWuibUePHtX19fUl9TMwMKBra2v1H/zBH5Sc8+DBg7qmpmbUdovFYjnd9PX1aUC/733vG/VZT0+PPnLkSPQTbzNvu+02Deg///M/H3XcWG3rXXfdpYUQurOzM9r2oQ99SLe2tpZoxerVq0va6jVr1mhA33vvvePew9atW7WUUr///e8fpTtKqWOW684779SZTEbncrmSe5syZUr091NPPaUBfffdd5cc+9BDD425vZxyHdZaa0Ank8kSff3Wt76lAd3S0hLpu9Zaf+ELXxilxSdaxwsXLtSTJ0/WAwMD0bbHH39cA2/qPVrentiwN8tpZ2BgACDyTIyH+by/v79k+yc+8YnjXuOhhx4C4I//+I9Ltn/6058+4XKed955JZ6ppqYm5syZw44dO6JtyWQyig8Pw5CjR49SWVnJnDlzWL169Qlf63hUVlZyyy23RH/PmTOH2tpa5s2bVzKKaX6PlzGdTke/+77P0aNHmTlzJrW1tSVlfOihh7j00ktZvHhxtK2+vj4K8TA88sgj9Pb28qEPfYiurq7ox3EcLr74Yn7729++afdtsVgsbwZGRyorK0d9dvXVV9PU1BT9fP3rXx+1zx/90R+N2hZvW4eGhujq6uKyyy5Da10S5vbRj36U/fv3l7SNd999N+l0mptuugkg8uz8+te/Znh4eMx7+NnPfoZSii9+8Yuj5iXFw83i5RoYGKCrq4srr7yS4eFhNm3aNOa5oehlqamp4brrritp25ctW0ZlZeVJt+3XXnttSTSA0ambbrqppB9wPP0ar47379/P+vXr+ehHP1ryfJcvX87ChQtPyT1azmxs2JvltGMaO2MEjcd4RtK0adOOe43Ozk6klKP2nTlz5gmXs729fdS2urq6krhgpRT/+I//yDe+8Q127txZElPd0NBwwtc6HpMnTx4VS11TU1MSm262ASVlzGaz3HXXXXzve99j3759JaGC8Vjyzs5OLr300lHXLq+zrVu3AvCOd7xjzLJWV1efyC1ZLBbLKcPoyODg4KjPvvWtbzEwMMChQ4f4yEc+Mupz13WZPHnyqO27d+/mi1/8Ij//+c9HzReJt63XXXcdEydO5O677+b
"text/plain": [
"<Figure size 1000x1000 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"python_book = cv.imread(\"img/book-python-cover.jpg\", cv.IMREAD_COLOR)\n",
"python_book_gray = cv.cvtColor(python_book, cv.COLOR_BGR2GRAY)\n",
"\n",
"plt.figure(figsize=[10,10])\n",
"plt.subplot(121)\n",
"plt.imshow(python_book[:,:,::-1])\n",
"plt.title('Original image')\n",
"plt.subplot(122)\n",
"plt.imshow(python_book_gray, cmap='gray')\n",
"plt.title('Grayscale image');"
]
},
{
"cell_type": "markdown",
"id": "bed58e13",
"metadata": {},
"source": [
"Jednym z najpopularniejszych (i nieopatentowanych) algorytmów wykrywania i opisywania punktów kluczowych jest [ORB](https://docs.opencv.org/4.5.3/d1/d89/tutorial_py_orb.html) ([dokumentacja](https://docs.opencv.org/4.5.3/db/d95/classcv_1_1ORB.html)). Poniżej znajduje się wizualizacja wykrytych punktów kluczowych:"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "be60009c",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"orb_alg = cv.ORB_create()\n",
"\n",
"keypoints_1 = orb_alg.detect(python_book_gray, None)\n",
"\n",
"keypoints_1, descriptors_1 = orb_alg.compute(python_book_gray, keypoints_1)\n",
"\n",
"python_book_keypoints = cv.drawKeypoints(python_book, keypoints_1, None, color=(0,255,0), \n",
" flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)\n",
"\n",
"plt.figure(figsize=(10,10))\n",
"plt.imshow(python_book_keypoints[:,:,::-1])\n",
"plt.title('Image keypoints');"
]
},
{
"cell_type": "markdown",
"id": "146432b4",
"metadata": {},
"source": [
"# Łączenie punktów kluczowych\n",
"\n",
"Załóżmy, że chcemy sprawdzić czy na danym zdjęciu znajduje się okładka powyższej książki:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "9556cf9a",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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ggoqqKBjQX/zN3/Dhg0buPTSS+d1XRRFXHfddVxxxRX8h//wH1Ke+Y1vfIOZmRk++MEPsnDhQn7+85/zpS99ieeee45vfOMbALz1rW/lwx/+MHfddRcXXXRRW7133XUXV199NStXrqTRaHDddddRr9f56Ec/yrJly9i1axd/8zd/w/j4OMPDwwD89m//Nr/1W7/Fq171Kj7zmc9QLpf52c9+xt13383rXvc6wBj0BgYG+MQnPsHAwAB33303n/70p5mYmODzn/9813u94447+NrXvsa73/1uPvaxj7F9+3b+4A/+gAceeIB77rmHUqk0r7EDA2D++q//mg9/+MMA3Hnnndxwww188pOf5Mtf/jIf+tCHGBsb43Of+xzvec97uPvuu9Nr5zLGAN/61rd4+9vfznnnncedd97J2NgY733ve1m5cuWLco8FneCkCyroONP4+LgG9Jve9Kau5d74xjdqQE9MTGittf7N3/xNDeibb765o6w9Z+m+++7TgP74xz/eVu7222/XgP7N3/zN9NhXv/pVDejt27enx9asWaMB/fd///fpsX379ulKpaJ/9Vd/NT1Wq9V0HMdtbWzfvl1XKhX9mc98pu0YoL/61a92vecf/OAHGtA/+MEP0mNXXXWVBvRf/MVfpMeeeOIJDWgppf7pT3+aHv/bv/3bjnZmZmY62rn33ns1oP/sz/4sPfbRj35UCyH0Aw88kB47ePCgXrBgQdv4TE5O6pGREf2+972vrc49e/bo4eHhjuMFFVRQQcebDh8+rAH95je/uePc2NiY3r9/f/rn8szbbrtNA/pf/at/1XFdFm+98847tRBC79y5Mz1288036xUrVrTJivvvv7+NVz/wwAMa0N/4xjdy72HLli1aSqnf8pa3dMgdpVTXft1xxx26r69P12q1tntbs2ZN+vvHP/6xBvRdd93Vdu13vvOdzOM++XJYa60BXalU2uTrV77yFQ3oZcuWpfJda60/9alPdcjiuY7xeeedp1etWqUnJyfTYz/84Q81cEzvsaCTk4qwt4KOO01OTgKknok8sucnJibajn/gAx+YtY3vfOc7AHzoQx9qO/7Rj350zv3ctGlTm2dq8eLFnHXWWWzbti09VqlU0vjwOI45ePAgAwMDnHXWWdx///1zbms2GhgY4Kabbkp/n3XWWYyMjLBx48Y2K6b97vaxt7c3/d5sNjl48CAbNmxgZGSkrY/f+c53uOyyy7jwwgvTYwsWLEhDPCx997vfZXx8nJtvvpkDBw6kf0EQcOmll/KDH/zgmN13QQUVVNCxICtHBgYGOs5dffXVLF68OP37T//pP3WU+eAHP9hxzOWt09PTHDhwgFe96lVordvC3N71rnexe/fuNt5411130dvby4033giQenb+9m//lpmZmcx7+Ku/+iuUUnz605/uWJfkhpu5/ZqcnOTAgQNceeWVzMzM8MQTT2TWDcbLMjw8zGtf+9o23n7xxRczMDBwxLz9Na95TVs0gJVTN954Y5seMJv8yhvj3bt38/DDD/Oud72r7fleddVVnHfeeS/KPRZ0YlMR9lbQcSfL7CwIyqM8kLRu3bpZ29i5cydSyo6yGzZsmHM/TzvttI5jo6OjbXHBSim++MUv8uUvf5nt27e3xVQvXLhwzm3NRqtWreqIpR4eHm6LTbf
"text/plain": [
"<Figure size 1000x1000 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"book_in_hands = cv.imread(\"img/book-python-in-hands.jpg\", cv.IMREAD_COLOR)\n",
"book_in_hands_gray = cv.cvtColor(book_in_hands, cv.COLOR_BGR2GRAY)\n",
"\n",
"plt.figure(figsize=[10,10])\n",
"plt.subplot(121)\n",
"plt.imshow(book_in_hands[:,:,::-1])\n",
"plt.title('Original image')\n",
"plt.subplot(122)\n",
"plt.imshow(book_in_hands_gray, cmap='gray')\n",
"plt.title('Grayscale image');"
]
},
{
"cell_type": "markdown",
"id": "f4608507",
"metadata": {},
"source": [
"Na początku znajdźmy i opiszmy punkty kluczowe. Oba kroki możemy wykonać jednocześnie przy pomocy metody `detectAndCompute()`:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "091c3868",
"metadata": {},
"outputs": [],
"source": [
"orb_alg = cv.ORB_create(nfeatures=1000)\n",
"\n",
"keypoints_1, descriptors_1 = orb_alg.detectAndCompute(python_book_gray, None)\n",
"keypoints_2, descriptors_2 = orb_alg.detectAndCompute(book_in_hands_gray, None)"
]
},
{
"cell_type": "markdown",
"id": "46df3c03",
"metadata": {},
"source": [
"Jeśli uda nam się połączyć odpowiadające sobie punkty kluczowe i wyliczyć macierz homografii, to z dość dużą dozą pewności będziemy mogli przyjąć, że na zdjęciu znajduje się szukany obiekt i będziemy mogli z grubsza wskazać gdzie on się znajduje. Punkty kluczowe są opisane przez wektory, więc np. moglibyśmy [*brute-forcem* i odległością Hamminga](https://docs.opencv.org/4.5.3/d3/da1/classcv_1_1BFMatcher.html) poszukać najlepszych odpowiedników. W poniższym przypadku pozostawimy 5% najlepszych dopasowań i zwizualizujemy te dopasowania:"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "9a660b70",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"matcher = cv.DescriptorMatcher_create(cv.DESCRIPTOR_MATCHER_BRUTEFORCE_HAMMING)\n",
"matches = matcher.match(descriptors_1, descriptors_2, None)\n",
"\n",
"matches.sort(key=lambda x: x.distance, reverse=False) # sort by distance\n",
"\n",
"num_good_matches = int(len(matches) * 0.05) # save 5%\n",
"matches = matches[:num_good_matches]\n",
"\n",
"image_matched = cv.drawMatches(python_book, keypoints_1, book_in_hands, keypoints_2, matches, None)\n",
"plt.figure(figsize=(10,10))\n",
"plt.imshow(image_matched[...,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "d4d41002",
"metadata": {},
"source": [
"Jak widać część punktów jest niepoprawnie dopasowana. Na szczęście obliczenie macierzy homografii odbywa się przy pomocy algorytmu [RANSAC](https://en.wikipedia.org/wiki/Random_sample_consensus) (ang. *random sample consensus*), co pozwala wziąć pod uwagę, że pewne odzwierciedlenia są złe. Aby oznaczyć miejsce występowania obiektu, transformujemy współrzędne narożników źródłowego zdjęcia przy użyciu otrzymanej macierzy i funkcji [`cv.perspectiveTransform()`](https://docs.opencv.org/4.5.3/d2/de8/group__core__array.html#gad327659ac03e5fd6894b90025e6900a7):"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "635c29f3",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"src_pts = np.float32([keypoints_1[m.queryIdx].pt for m in matches]).reshape(-1,1,2)\n",
"dst_pts = np.float32([keypoints_2[m.trainIdx].pt for m in matches]).reshape(-1,1,2)\n",
"\n",
"mat, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0)\n",
"matches_mask = mask.ravel().tolist()\n",
"height, width, _ = python_book.shape\n",
"\n",
"pts = np.float32([[0,0], [0,height-1], [width-1,height-1], [width-1,0]]).reshape(-1,1,2)\n",
"\n",
"dst = cv.perspectiveTransform(pts, mat)\n",
"\n",
"book_in_hands_poly = cv.polylines(book_in_hands,\n",
" [np.int32(dst)], True, (0,0,255), \n",
" 10, cv.LINE_AA)\n",
" \n",
"draw_params = dict(matchColor=(0,255,0),\n",
" matchesMask=matches_mask, # draw only inliers\n",
" flags=2) # NOT_DRAW_SINGLE_POINTS\n",
"image_matched = cv.drawMatches(python_book, keypoints_1, \n",
" book_in_hands_poly, keypoints_2, \n",
" matches, None, **draw_params)\n",
"\n",
"plt.figure(figsize=(10,10))\n",
"plt.imshow(image_matched[...,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "c1580cf1",
"metadata": {},
"source": [
"# Zadanie 1\n",
"\n",
"Napisz interaktywną aplikację przy pomocy HighGUI, która pozwoli na obrazie `img/billboards.jpg` wybrać 4 punkty i umieścić w zaznaczonym obszarze wybrany obraz, np. `img/bakery.jpg`.\n",
"\n",
"![Aplikacja](img/app-billboard.png)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "11ecb6b1-da23-497d-b964-acfcee93e51a",
"metadata": {},
"outputs": [],
"source": [
"import cv2 as cv\n",
"import numpy as np\n",
"class CloseApp(Exception): pass\n",
"\n",
"def mouse_handler(event, x, y, flags, data) :\n",
" \n",
" if event == cv.EVENT_LBUTTONDOWN :\n",
" cv.circle(data['im'], (x,y),3, (0,0,255), 5, 16);\n",
" cv.imshow(\"Image\", data['im']);\n",
" if len(data['points']) < 4 :\n",
" data['points'].append([x,y])\n",
"\n",
"def get_four_points(im):\n",
" \n",
" # Set up data to send to mouse handler\n",
" data = {}\n",
" data['im'] = im.copy()\n",
" data['points'] = []\n",
" \n",
" #Set the callback function for any mouse event\n",
" cv.imshow(\"Image\",im)\n",
" cv.setMouseCallback(\"Image\", mouse_handler, data)\n",
" k = cv.waitKey(0) & 0xFF\n",
" if k == 27:\n",
" cv.destroyAllWindows()\n",
" cv.waitKey(1)\n",
" raise CloseApp\n",
" \n",
" # Convert array to np.array\n",
" points = np.vstack(data['points']).astype(float)\n",
" \n",
" return points"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3f83d357-9b37-40ef-bad4-fa0216c74359",
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n",
"try: \n",
" while(True):\n",
"\n",
" # Read source image.\n",
" im_src = cv.imread(\"img/bakery.jpg\")\n",
" size = im_src.shape\n",
"\n",
" # Create a vector of source points.\n",
" pts_src = np.array([[0,0], [size[1] - 1, 0], [size[1] - 1, size[0] -1], [0, size[0] - 1 ]],dtype=float);\n",
"\n",
" # Read destination image\n",
" im_dst = cv.imread(\"img/billboards.jpg\")\n",
"\n",
" # Get four corners of the billboard\n",
" pts_dst = get_four_points(im_dst)\n",
"\n",
" # Calculate Homography between source and destination points\n",
" h, status = cv.findHomography(pts_src, pts_dst)\n",
"\n",
" # Warp source image\n",
" im_temp = cv.warpPerspective(im_src, h, (im_dst.shape[1],im_dst.shape[0]))\n",
"\n",
" # Black out polygonal area in destination image.\n",
" cv.fillConvexPoly(im_dst, pts_dst.astype(int), 0, 16)\n",
"\n",
" # Add warped source image to destination image.\n",
" im_dst = im_dst + im_temp\n",
"\n",
" # Display image.\n",
" cv.imshow(\"Image\", im_dst)\n",
" cv.waitKey(0)\n",
" \n",
"except CloseApp:\n",
" pass"
]
},
{
"cell_type": "markdown",
"id": "e6b25af6",
"metadata": {
"tags": []
},
"source": [
"# Zadanie 2\n",
"\n",
"Załóżmy, że mamy dwa zdjęcia, które chcielibyśmy połączyć w panoramę:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "becb6541",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x1000 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"boat_1 = cv.imread(\"img/boat_1.jpg\", cv.IMREAD_COLOR)\n",
"boat_2 = cv.imread(\"img/boat_2.jpg\", cv.IMREAD_COLOR)\n",
"\n",
"plt.figure(figsize=[10,10])\n",
"plt.subplot(121)\n",
"plt.imshow(boat_1[:,:,::-1])\n",
"plt.title('Image 1')\n",
"plt.subplot(122)\n",
"plt.imshow(boat_2[:,:,::-1])\n",
"plt.title('Image 2');"
]
},
{
"cell_type": "markdown",
"id": "35873eb0",
"metadata": {},
"source": [
"Standardowo w OpenCV panoramę tworzy się przy pomocy klasy [`Stitcher`](https://docs.opencv.org/4.5.3/d2/d8d/classcv_1_1Stitcher.html), której można podać listę zdjęć do połączenia:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "3d35782b",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 2000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"stitcher_alg = cv.Stitcher_create()\n",
"_, panorama = stitcher_alg.stitch([boat_1, boat_2])\n",
"plt.figure(figsize=[20,10]) \n",
"plt.imshow(panorama[:,:,::-1])\n",
"plt.title('Panorama');"
]
},
{
"cell_type": "markdown",
"id": "73464452",
"metadata": {},
"source": [
"Spróbuj zaimplementować samodzielne stworzenie panoramy. Poniższy efekt będzie wystarczający, aczkolwiek możesz również spróbować zniwelować widoczną różnicę w intensywnościach na granicy zdjęć."
]
},
{
"cell_type": "markdown",
"id": "965e871e",
"metadata": {},
"source": [
"![Panorama](img/panorama-manual.png)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "a4b7e06a",
"metadata": {},
"outputs": [],
"source": [
"# miejsce na eksperymenty\n",
"class Image_Stitching():\n",
" def __init__(self) :\n",
" self.ratio=0.85\n",
" self.min_match=10\n",
" self.sift=cv.xfeatures2d.SIFT_create()\n",
" self.smoothing_window_size=800\n",
"\n",
" def registration(self,img1,img2):\n",
" kp1, des1 = self.sift.detectAndCompute(img1, None)\n",
" kp2, des2 = self.sift.detectAndCompute(img2, None)\n",
" matcher = cv.BFMatcher()\n",
" raw_matches = matcher.knnMatch(des1, des2, k=2)\n",
" good_points = []\n",
" good_matches=[]\n",
" for m1, m2 in raw_matches:\n",
" if m1.distance < self.ratio * m2.distance:\n",
" good_points.append((m1.trainIdx, m1.queryIdx))\n",
" good_matches.append([m1])\n",
" img3 = cv.drawMatchesKnn(img1, kp1, img2, kp2, good_matches, None, flags=2)\n",
" cv.imwrite('matching.jpg', img3)\n",
" if len(good_points) > self.min_match:\n",
" image1_kp = np.float32(\n",
" [kp1[i].pt for (_, i) in good_points])\n",
" image2_kp = np.float32(\n",
" [kp2[i].pt for (i, _) in good_points])\n",
" H, status = cv.findHomography(image2_kp, image1_kp, cv.RANSAC,5.0)\n",
" return H\n",
"\n",
" def create_mask(self,img1,img2,version):\n",
" height_img1 = img1.shape[0]\n",
" width_img1 = img1.shape[1]\n",
" width_img2 = img2.shape[1]\n",
" height_panorama = height_img1\n",
" width_panorama = width_img1 +width_img2\n",
" offset = int(self.smoothing_window_size / 2)\n",
" barrier = img1.shape[1] - int(self.smoothing_window_size / 2)\n",
" mask = np.zeros((height_panorama, width_panorama))\n",
" if version== 'left_image':\n",
" mask[:, barrier - offset:barrier + offset ] = np.tile(np.linspace(1, 0, 2 * offset ).T, (height_panorama, 1))\n",
" mask[:, :barrier - offset] = 1\n",
" else:\n",
" mask[:, barrier - offset :barrier + offset ] = np.tile(np.linspace(0, 1, 2 * offset ).T, (height_panorama, 1))\n",
" mask[:, barrier + offset:] = 1\n",
" return cv.merge([mask, mask, mask])\n",
"\n",
" def blending(self,img1,img2):\n",
" H = self.registration(img1,img2)\n",
" height_img1 = img1.shape[0]\n",
" width_img1 = img1.shape[1]\n",
" width_img2 = img2.shape[1]\n",
" height_panorama = height_img1\n",
" width_panorama = width_img1 +width_img2\n",
"\n",
" panorama1 = np.zeros((height_panorama, width_panorama, 3))\n",
" mask1 = self.create_mask(img1,img2,version='left_image')\n",
" panorama1[0:img1.shape[0], 0:img1.shape[1], :] = img1\n",
" panorama1 *= mask1\n",
" mask2 = self.create_mask(img1,img2,version='right_image')\n",
" panorama2 = cv.warpPerspective(img2, H, (width_panorama, height_panorama))*mask2\n",
" result=panorama1+panorama2\n",
"\n",
" rows, cols = np.where(result[:, :, 0] != 0)\n",
" min_row, max_row = min(rows), max(rows) + 1\n",
" min_col, max_col = min(cols), max(cols) + 1\n",
" final_result = result[min_row:max_row, min_col:max_col, :]\n",
" return final_result\n",
" \n",
"def main(img1,img2):\n",
" final=Image_Stitching().blending(img1,img2)\n",
" cv.imwrite('panorama.jpg', final)\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "1b95f025-169b-4545-81cd-8aec1fe8517b",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[ WARN:0] global /tmp/pip-req-build-agffqapq/opencv_contrib/modules/xfeatures2d/misc/python/shadow_sift.hpp (13) SIFT_create DEPRECATED: cv.xfeatures2d.SIFT_create() is deprecated due SIFT tranfer to the main repository. https://github.com/opencv/opencv/issues/16736\n"
]
},
{
"data": {
"text/plain": [
"Text(0.5, 1.0, 'Panorama')"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA0cAAAGzCAYAAADkJmylAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9aax1W1YXjP/GmGvtfc7T3MZLUVVaRSwh1KsQNQGpoIAEiUgwhMQQEROIQaOpFIbwgciHF4MhYktERIL5mzI2BBNUSAhBhQ+EChCN2EQNvhEtRQ1FI1Rz73PO3muO8X4YzRxr7X3uLZD6V72XNauee87ZezWzGXOM32gnqapib3vb2972tre97W1ve9vb3n6dN/5od2Bve9vb3va2t73tbW9729vePhbarhztbW9729ve9ra3ve1tb3vbG3blaG9729ve9ra3ve1tb3vb294A7MrR3va2t73tbW9729ve9ra3vQHYlaO97W1ve9vb3va2t73tbW97A7ArR3vb2972tre97W1ve9vb3vYGYFeO9ra3ve1tb3vb2972tre97Q3ArhztbW9729ve9ra3ve1tb3vbG4BdOdrb3va2t73tbW9729ve9rY3ALtytLe97W1ve9vb3va2t73tbW8AduVob3vb29729n/Y/s7f+Tsgovx3c3ODT/7kT8a73vUuvO997/tod29ve9vb3va2tw+7TR/tDuxtb3vb295eH+3P/bk/h7e97W24u7vDe97zHnzHd3wHfuAHfgD//t//ezx69Oij3b297W1ve9vb3l6z7crR3va2t73t7dekfeEXfiE+/dM/HQDwx//4H8dLL72Eb/mWb8H3fd/34Y/8kT/yUe7daC+//DIeP3780e7G3va2t73t7WOw7WF1e9vb3va2t49I+7zP+zwAwH/9r/8Vf+Wv/BX87t/9u/HSSy/h9vYWn/Zpn4bv+Z7vubiHiPCud70L3/u934tP/dRPxfF4xKd8yqfgB3/wBy+u/df/+l/jC7/wC/Hcc8/hyZMn+H2/7/fhJ37iJ1bXRMjfj/zIj+Cd73wnPv7jPx5vectbAAD/7b/9N7zzne/E29/+dtze3uKll17Cl37pl+K9733v1We85z3vwZ/+038ab3jDG/DCCy/gT/7JP4nT6YRf/uVfxld8xVfgxRdfxIsvvoiv+7qvg6qunvHhjn9ve9vb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
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"main(boat_1, boat_2)\n",
"panorama_jpg = cv.imread(\"panorama.jpg\", cv.IMREAD_COLOR)\n",
"plt.figure(figsize=[10,10])\n",
"plt.imshow(panorama_jpg[:,:,::-1])\n",
"plt.title('Panorama')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b4eba8f8-337c-4f7f-afb8-5c703f0f4f22",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"author": "Andrzej Wójtowicz",
"email": "andre@amu.edu.pl",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"lang": "pl",
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
},
"subtitle": "05. Transformacje geometryczne i cechy obrazów [laboratoria]",
"title": "Widzenie komputerowe",
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}