wko/wko-07.ipynb

921 lines
3.0 MiB
Plaintext
Raw Normal View History

2023-01-16 09:35:16 +01:00
{
"cells": [
{
"cell_type": "markdown",
"id": "73e26798",
"metadata": {},
"source": [
"![Logo 1](img/aitech-logotyp-1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Widzenie komputerowe </h1>\n",
"<h2> 07. <i>Analiza wideo: przepływ optyczny, śledzenie obiektó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": "f124f5cd",
"metadata": {},
"source": [
"W poniższych materiałach zobaczymy w jaki sposób możemy przy pomocy przepływu optycznego dokonać stabilizacji obrazu oraz w jaki sposób śledzić obiekty znajdujące się na filmie.\n",
"\n",
"Na początku załadujmy niezbędne biblioteki."
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "ed69629c",
"metadata": {},
"outputs": [],
"source": [
"import cv2 as cv\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"import IPython.display"
]
},
{
"cell_type": "markdown",
"id": "f9ef8d67",
"metadata": {},
"source": [
"# Przepływ optyczny\n",
"\n",
"Naszym celem będzie znalezienie na poniższym filmie punktów kluczowych, które pozwolą nam w jakiś sposób sprawdzić jak przemieszcza się rowerzystka:"
]
},
{
"cell_type": "code",
"execution_count": 46,
"id": "1629fc29",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<video src=\"vid/bike.mp4\" controls width=\"800\" >\n",
" Your browser does not support the <code>video</code> element.\n",
" </video>"
],
"text/plain": [
"<IPython.core.display.Video object>"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"IPython.display.Video(\"vid/bike.mp4\", width=800)"
]
},
{
"cell_type": "markdown",
"id": "aa176c9a",
"metadata": {},
"source": [
"Załadujmy film:"
]
},
{
"cell_type": "code",
"execution_count": 47,
"id": "2463bd1d",
"metadata": {},
"outputs": [],
"source": [
"bike = cv.VideoCapture(\"vid/bike.mp4\")"
]
},
{
"cell_type": "markdown",
"id": "dde041a3",
"metadata": {},
"source": [
"Przy pomocy algorytmu Shi-Tomasi (rozwinięcie metody Harrisa) możemy znaleźć narożniki, które dobrze nadają się do śledzenia. W OpenCV algorytm jest zaimplementowany w funkcji [`cv.goodFeaturesToTrack()`](https://docs.opencv.org/4.5.3/dd/d1a/group__imgproc__feature.html#ga1d6bb77486c8f92d79c8793ad995d541):"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "36492aa6",
"metadata": {},
"outputs": [],
"source": [
"corners_num = 100\n",
"corners_colors = np.random.randint(0, 255, (corners_num, 3))\n",
"\n",
"_, frame_1 = bike.read()\n",
"frame_1_gray = cv.cvtColor(frame_1, cv.COLOR_BGR2GRAY)\n",
"keypoints_1 = cv.goodFeaturesToTrack(\n",
" frame_1_gray, mask=None, maxCorners=corners_num,\n",
" qualityLevel=0.3, minDistance=7, blockSize=7)\n",
"\n",
"mask = np.zeros_like(frame_1)\n",
"count = 0"
]
},
{
"cell_type": "markdown",
"id": "028dded7",
"metadata": {},
"source": [
"Aby sprawdzić w jaki sposób punkty przemieszczają się pomiędzy kolejnymi klatkami filmu, wykorzystamy algorytm LucasaKanade, który jest zaimplementowany w funkcji [`cv.calcOpticalFlowPyrLK()`](https://docs.opencv.org/4.5.3/dc/d6b/group__video__track.html#ga473e4b886d0bcc6b65831eb88ed93323):"
]
},
{
"cell_type": "code",
"execution_count": 49,
"id": "14b62820",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 700x700 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 700x700 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAl8AAAFiCAYAAADIs73zAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9SZBkSXrfCf5U326rm/nuER77mntWZi0ooAoAGyS6W7oplBHp4ZHCucwFvOBEXEjhiVceSJnjjIwIR0iZlhl2T5MEhgBYAAqoQqJyX2LJWDx8dzd3283eqqpzeGbu5ltEZGahUNPw/yHC7T19ui9//b5PPxXGGMM5znGOc5zjHOc4xzl+IZB/0xk4xznOcY5znOMc5/jbhHPydY5znOMc5zjHOc7xC8Q5+TrHOc5xjnOc4xzn+AXinHyd4xznOMc5znGOc/wCcU6+znGOc5zjHOc4xzl+gTgnX+c4xznOcY5znOMcv0Cck69znOMc5zjHOc5xjl8gzsnXOc5xjnOc4xznOMcvEOfk6xznOMc5znGOc5zjF4hz8nWOc5zjHOc4xznO8QvELzX5+jf/5t9w5coVfN/nu9/9Lu+9997fdJbOcY5znOMc5zjHOb4RfmnJ17//9/+e3/3d3+Wf//N/zgcffMCbb77Jb//2b7O7u/s3nbVznOMc5zjHOc5xjq8N8ct6sfZ3v/tdvv3tb/Ov//W/BkBrzfLyMv/kn/wT/uk//ad/w7k7xznOcY5znOMc5/h6sP+mM3AakiTh/fff5/d+7/cOnkkp+a3f+i1+8pOfnPpNHMfEcXzwW2tNs9lkenoaIcRfe57PcY5znOMc5zjH314YY+j1eiwtLSHl8xWLv5Tka29vD6UU8/PzR57Pz89z//79U7/5l//yX/Iv/sW/+EVk7xznOMc5znGOc5zjVKytrXHx4sXnhvmlJF9fB7/3e7/H7/7u7x787nQ6XLp0if/Xz1YolioAaGM4rmOV8JUlY6fF8zI4ntZZGt8Xh5G8TAYMkGlFnMTYjs3a2joFL6AQBDi2g2O5mFFaUkikFCDMQZpSSgwGxFevoxN5MebM8h6FPAhnTJ4vgwZAIIiGQ5qtfWbn5ui0O9RqNWzHQU/GLThSP0optne2EQJ8x6FUKKAxSClpdZoM+n3Qinqtyv0HX7I4O0+lVsN2bHq9DtVqiTAa0tjZZnN9jbg/wGjDjVt3cdwCOA5BsUC7u8dnn7xP2Q+4OL/EVHWK9c0NNrd3mKnPMz27SLU+w/TMHMMwxLYcOu02hVIBKQXlqSqWZZGqDGnZ7O/tUiwU6Q9DgqBIuVTClhbaCIQUJGlMt9Oj0djl4tIS1eoUcRKx39yjPlVDKc32boOlxSVcxz2snoO2NOTVZkjTFADHcQ/eG9SRb76KgcJhCqOGPBHgxf3p+CgTnP3NZN86GUoelPPlIU7EpF/qO3OkuAZAnDLr/LyMPYw5vX5f9nM4UWGGk/OOKwS+Vvzlj/6AH//Bf8AmIouHDIcDMqVAgOu6CNui3W7nf0uBzgyubVMolBkSUFm+wz/8P/2fKdfrKD2qUZPXtTCHQ9eM8iRH7XZa3Z/aG070qwnpgzEnm0KcbFf5NarTcKwuR2URBjQmL485rVe9GNqc8oX56vG8DE6fp8fzgQajsDKFThLWn63wyScfU65WeP2tt3D9AgZDsRggLRsrS4n7e3RbG2xtr/L00QOKnofvWHQ7bXZ2N0mTiFQZlJFIIRkMY4ztUZ+5wIUL17i0fA2hDJKEStFG02fQb6LSiJ39PVZ296hduMYPfuu/wwumsISPjQAlIMvQ8ZCw32J3e4PdrTV8YXh473M2dtbQOsHC4CKwDXTaLdJUIT0Ht1zCLRR46623cNyAOIro93r02h1AMhgOsS2ffhgSJhkKjRe4VKsV/vB//Z8pl8svrOtfSvI1MzODZVns7Owceb6zs8PCwsKp33ieh+d5J54XSxWK5V9O8vW1cDDCX7wQGWAwHNIbhkRpSKJSSm4RaUmEZeF6PlJaCPLFXFgCBBijAIHrujmp+QWQL2MMQkiEkGitD8iA53n5d8YAgmKpglcoEIYh0nawXY9iuYzWE1PoxAQ4TtN2HD7//GMGnX0uLixigHKlBEnI7sYzlpYWEEbR7zSxF+YJXAstMtqtLXa3IwCmKlXKhTJFr0i9XqfVaiOtAW+8/S2qUxXu3W8yM11hb2udHdWju+cwGA65euEiM3PLYBfRQGN/j1KpwvziApeuXCZJErIsRWvFbmOTRCfU6zOkyZDC9BRhGOFYNpVSGSklmQJlFFoYylMV9lv7FMplvMBnGA1ZWFjE9Ty2t3cplksUyyVc93Bs5G2Z10s4DBkMB4CgUCgQBMExcmYmvnmZhj7t54s3GSejOTnGRkv0YRhz9Iuzk/pqxHH8jRCHC7cZj/nnVMNp/VufUo6vtwQfTwwEBqN//ia75jjZMQYPQdzaRytNsViAVONYBiHyzY2QAtdz0UKgtc43bsaQSYUtJHEaE2KhOm2iOGGxXCVTatQuLyJfp5PEl8Mk+TpZ82eSpiPFf3Ed/7WSr+NfGfM3R77QWAji/oDa4kV+MLdAtVbDL1VRWiOFxhIgVcrmykO+/OJnxFGL2dk6d+7ewTbQ77TZa+yilSbT4AVFBrEmEwGF2Smu3HyDb3/vB1xcvoxQBqKIuNfk84//nNXVL4iSDoFrs9tuYheKeIWAD372PosLl/G9MkIZHty7h8lCamUfaRIsk5ElLe6trJAlCUHgEoUpRilm5ub5uz/4DbY3N3n48CErmxu0u108rbl37x6eW8DzAzzHBWMRFApcvXYDxw3Y63SYX7qIsCS+7zFdm+IP/9f/+aXmy19K8uW6Lu+88w5/9Ed/xD/4B/8AyG24/uiP/ojf+Z3f+drx/rw661eN569jejwdec4m211pRafbRkhFGHfZ2w8pBWXSWHFl+SqW5WCMwbIshM4JmDEGx3HRWqONOaK7Hqf8or51RBAlBEJMPjPHwpojYZXK6HTa2LZN4Ln5YpDzQiwpqVQqdLtdNjY2UFmG3+0yOzuL5dg54TpIxYAwxGFE2OsyUy2x8eQz2tvPcGyH6zduMl2vY+IuW8967EqL2YqPJ1PWn35Bt9fCsgwba2uUilO4SJaWLjA9M8fa6hqVqRq7O9sMey1MNqDf3kVFA6wsIux06acJWhnm6tPs7+7QT+Ctb3+bMEmxXRvf99Ha0Ol0sSxBq7XH+vpjuu0dyqUSIHGFwraLlAMXdIbS0Gr3cFyXUrlE4qTYjsv65gbVSgVbSobDjHa7jSUlU9VpUAatVE60RU5fhBAkScLO7g6+H7AwP4e0rNHke9hGz51EXrpjv6iznBL8LBL1ou/OilpM/DLjxez5BTCTnemsNI8lfzJL4muM/+d9cbSQuUTyq6ZwNI7jBNmcyHXeZzrtDnt7e7iui+MW0EqQpSFa531L6ZRUKYTQo/gE0spjjDNNIuHS0kWmpqaQgEQcIadjsoIYfT1iNAJeLCw88+XJ3YA59tac0nCnRfd11o9RcTCnkKWXb+VjYQWIU9v8RTk85ZtTWK0Y/XM4XY83HvkTbcAuFJgrFtBZimVZGCGQUiI1WDphb+MJu6v3cWVEKhN2djZIopjAcVh/tsKgPyAoVFFhRGZcLl69ysKVO8xdvMHFyzeoVqoIlZJFPQbtHdZX7rO1+ZiN9RXSLASjSXVGoDT33n+f/iCjVKjiuwWKgY/JhthSEwYWg06PaJCgsxTHFriOhdaKKI4oFQK+/d3vcPXGNYp+wNPHT8AYbNtCChgM+3hegWKhTLczJBpqojik03mK7TpoqRESpudm6SVDeu29F7TBIX4pyRfA7/7u7/KP/tE/4t133+U73/kO/+pf/SsGgwH/+B//468d53jh+ab4KvH83InXQcIndBunhDO4nk0cD8BOUWbI+toOC3OLdFtDFufmcJ0gH1xaIC0Jxs6JmDQkaYwtLYzWYOVdxQhxoII6JFSHC7YYvYexNGu80AlyDmcYS1SOLxq5gEujVUaztQ9KUyuXcBwnl2wJiRp9OzM3y7PVVR4+fMitmzf
"text/plain": [
"<Figure size 700x700 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 700x700 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 700x700 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 700x700 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 700x700 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 700x700 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"while True:\n",
" _, frame_2 = bike.read()\n",
" frame_2_gray = cv.cvtColor(frame_2, cv.COLOR_BGR2GRAY)\n",
" count += 1\n",
"\n",
" keypoints_2, status, _ = cv.calcOpticalFlowPyrLK(\n",
" frame_1_gray, frame_2_gray, keypoints_1, None, winSize=(15, 15),\n",
" maxLevel=2, criteria=(cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))\n",
"\n",
" keypoints_2_good = keypoints_2[status==1]\n",
" keypoints_1_good = keypoints_1[status==1]\n",
" \n",
" for i, (kp2, kp1) in enumerate(zip(keypoints_2_good, keypoints_1_good)):\n",
" a, b = kp2.ravel()\n",
" a, b = int(a), int(b)\n",
" c, d = kp1.ravel()\n",
" c, d = int(c), int(d)\n",
" cv.line(mask, (a, b), (c, d), corners_colors[i].tolist(), 8, cv.LINE_AA)\n",
" cv.circle(frame_2, (a ,b), 9, corners_colors[i].tolist(), -1)\n",
" \n",
" display_frame = cv.add(frame_2, mask)\n",
" if count % 5 == 0:\n",
" plt.figure(figsize=(7,7))\n",
" plt.imshow(display_frame[:,:,::-1])\n",
" if count > 40:\n",
" break\n",
"\n",
" frame_1_gray = frame_2_gray.copy()\n",
" keypoints_1 = keypoints_2_good.reshape(-1,1,2)\n",
" \n",
"bike.release()"
]
},
{
"cell_type": "markdown",
"id": "d8c01f59",
"metadata": {},
"source": [
"Możemy zauważyć, że część punktów kluczowych została wykryta poza głównym śledzonym obiektem, jednak mimo wszystko jesteśmy w stanie określić główny ruch przemieszczającego się obiektu."
]
},
{
"cell_type": "markdown",
"id": "879a813e",
"metadata": {},
"source": [
"## Stabilizacja obrazu\n",
"\n",
"Spróbujemy wykorzystać przepływ optyczny do stablizacji cyfrowej filmu nakręconego z ręki:"
]
},
{
"cell_type": "code",
"execution_count": 50,
"id": "d8686953",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<video src=\"vid/protest.mp4\" controls width=\"800\" >\n",
" Your browser does not support the <code>video</code> element.\n",
" </video>"
],
"text/plain": [
"<IPython.core.display.Video object>"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"IPython.display.Video(\"vid/protest.mp4\", width=800)"
]
},
{
"cell_type": "markdown",
"id": "c3541db4",
"metadata": {},
"source": [
"Załadujmy film oraz przygotujmy film wyjściowy, który będziemy wyświetlać obok oryginalnego, tak aby móc porównać otrzymane wyniki:"
]
},
{
"cell_type": "code",
"execution_count": 51,
"id": "0b18aad1",
"metadata": {},
"outputs": [],
"source": [
"cap = cv.VideoCapture(\"vid/protest.mp4\")\n",
"n_frames = int(cap.get(cv.CAP_PROP_FRAME_COUNT))\n",
"width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH)) \n",
"height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))\n",
"fps = cap.get(cv.CAP_PROP_FPS)\n",
"\n",
"out = cv.VideoWriter('vid/gen-protest.avi', cv.VideoWriter_fourcc(*'MJPG'), fps, (width*2, height))"
]
},
{
"cell_type": "markdown",
"id": "27355bd0",
"metadata": {},
"source": [
"Pomiędzy poszczególnymi klatkami filmu znajdujemy punkty kluczowe i śledzimy w jaki sposób się one przemieściły. Na tej podstawie przy pomocy [`cv.estimateAffinePartial2D()`](https://docs.opencv.org/4.5.3/d9/d0c/group__calib3d.html#gad767faff73e9cbd8b9d92b955b50062d) możemy oszacować transformacje (translację oraz obrót), które nastapiły między następującymi po sobie klatkami:"
]
},
{
"cell_type": "code",
"execution_count": 52,
"id": "c00b1e9d",
"metadata": {},
"outputs": [],
"source": [
"_, prev = cap.read()\n",
"prev_gray = cv.cvtColor(prev, cv.COLOR_BGR2GRAY)\n",
"\n",
"transforms = np.zeros((n_frames-1, 3), np.float32)\n",
"\n",
"for i in range(n_frames-2):\n",
" prev_pts = cv.goodFeaturesToTrack(prev_gray, maxCorners=200,\n",
" qualityLevel=0.01, minDistance=30, blockSize=3)\n",
" \n",
" success, curr = cap.read() \n",
" if not success: \n",
" break\n",
" curr_gray = cv.cvtColor(curr, cv.COLOR_BGR2GRAY) \n",
" \n",
" curr_pts, status, _ = cv.calcOpticalFlowPyrLK(prev_gray, curr_gray, prev_pts, None)\n",
" \n",
" idx = np.where(status==1)[0]\n",
" prev_pts = prev_pts[idx]\n",
" curr_pts = curr_pts[idx]\n",
" \n",
" mat, _ = cv.estimateAffinePartial2D(prev_pts, curr_pts)\n",
" # traslation\n",
" dx = mat[0,2]\n",
" dy = mat[1,2]\n",
" # rotation angle\n",
" da = np.arctan2(mat[1,0], mat[0,0])\n",
" \n",
" transforms[i] = [dx,dy,da]\n",
" \n",
" prev_gray = curr_gray"
]
},
{
"cell_type": "markdown",
"id": "ba9fce7d",
"metadata": {},
"source": [
"Przygotujemy też kilka funkcji pomocniczych. Posiadając serię transformacji wygładzimy ich poszczególne komponenty przy pomocy średniej kroczącej."
]
},
{
"cell_type": "code",
"execution_count": 53,
"id": "0fd89a26",
"metadata": {},
"outputs": [],
"source": [
"def moving_average(values, radius): \n",
" window_size = 2 * radius + 1 \n",
" mask = np.ones(window_size)/window_size \n",
"\n",
" values_padded = np.lib.pad(values, (radius, radius), 'edge') \n",
" values_smoothed = np.convolve(values_padded, mask, mode='same') \n",
" \n",
" return values_smoothed[radius:-radius] # remove padding\n",
"\n",
"def smooth(trajectory, radius=50): \n",
" smoothed_trajectory = np.copy(trajectory) \n",
" for i in range(smoothed_trajectory.shape[1]):\n",
" smoothed_trajectory[:,i] = moving_average(trajectory[:,i], radius)\n",
"\n",
" return smoothed_trajectory"
]
},
{
"cell_type": "markdown",
"id": "9f4d1df0",
"metadata": {},
"source": [
"Możemy teraz policzyć jakie mieliśmy transformacje względem początku filmu, wygładzić je poprzez średnią kroczącą, a następnie nanieść wynikowe różnice na poszczególne transformacje:"
]
},
{
"cell_type": "code",
"execution_count": 54,
"id": "efb52c4d",
"metadata": {},
"outputs": [],
"source": [
"trajectory = np.cumsum(transforms, axis=0)\n",
"smoothed_trajectory = smooth(trajectory) \n",
"\n",
"difference = smoothed_trajectory - trajectory\n",
"transforms_smooth = transforms + difference"
]
},
{
"cell_type": "markdown",
"id": "0ef3b313",
"metadata": {},
"source": [
"Ostatecznie na podstawie wygładzonych transformacji dostosowujemy poszczególne klatki filmu. Dodatkowo poprzez ustabilizowanie obrazu mogą pojawić się czarne obramowania na wynikowym obrazie, zatem poprzez niewielkie powiększenie obrazu zniwelujemy ten efekt:"
]
},
{
"cell_type": "code",
"execution_count": 55,
"id": "b8d4528b",
"metadata": {},
"outputs": [],
"source": [
"cap.set(cv.CAP_PROP_POS_FRAMES, 0) # back to first frame\n",
"\n",
"for i in range(n_frames-2):\n",
" success, frame = cap.read() \n",
" if not success:\n",
" break\n",
"\n",
" dx = transforms_smooth[i,0]\n",
" dy = transforms_smooth[i,1]\n",
" da = transforms_smooth[i,2]\n",
"\n",
" mat = np.zeros((2,3), np.float32)\n",
" mat[0,0] = np.cos(da)\n",
" mat[0,1] = -np.sin(da)\n",
" mat[1,0] = np.sin(da)\n",
" mat[1,1] = np.cos(da)\n",
" mat[0,2] = dx\n",
" mat[1,2] = dy\n",
"\n",
" frame_stabilized = cv.warpAffine(frame, mat, (width, height))\n",
" \n",
" mat = cv.getRotationMatrix2D((width/2, height/2), 0, 1.1)\n",
" frame_stabilized = cv.warpAffine(frame_stabilized, mat, (width, height))\n",
"\n",
" frame_out = cv.hconcat([frame, frame_stabilized]) # frame by frame\n",
" \n",
" out.write(frame_out)\n",
" \n",
"out.release()"
]
},
{
"cell_type": "markdown",
"id": "c204ec3a",
"metadata": {},
"source": [
"Na potrzeby wyświetlenie wynikowego filmu w przeglądarce, użyjemy kodeka H264:"
]
},
{
"cell_type": "code",
"execution_count": 56,
"id": "4b58bce1",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"'ffmpeg' is not recognized as an internal or external command,\n",
"operable program or batch file.\n"
]
}
],
"source": [
"!ffmpeg -y -hide_banner -loglevel warning -nostats -i vid/gen-protest.avi -vcodec libx264 vid/gen-protest.mp4"
]
},
{
"cell_type": "markdown",
"id": "fce1d5cd",
"metadata": {},
"source": [
"Wynikowy film:"
]
},
{
"cell_type": "code",
"execution_count": 57,
"id": "041e29a5",
"metadata": {},
"outputs": [
{
"ename": "ValueError",
"evalue": "To embed videos, you must pass embed=True (this may make your notebook files huge)\nConsider passing Video(url='...')",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_20516\\999644078.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mIPython\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdisplay\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mVideo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"vid/gen-protest.mp4\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mwidth\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m800\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0membed\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32mc:\\Users\\48516\\anaconda3\\envs\\widzenie_komputerowe\\lib\\site-packages\\IPython\\core\\display.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, data, url, filename, embed, mimetype, width, height, html_attributes)\u001b[0m\n\u001b[0;32m 1408\u001b[0m \u001b[1;34m\"Consider passing Video(url='...')\"\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1409\u001b[0m ])\n\u001b[1;32m-> 1410\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 1411\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1412\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmimetype\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmimetype\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mValueError\u001b[0m: To embed videos, you must pass embed=True (this may make your notebook files huge)\nConsider passing Video(url='...')"
]
}
],
"source": [
"IPython.display.Video(\"vid/gen-protest.mp4\", width=800, embed=False)"
]
},
{
"cell_type": "markdown",
"id": "5fd935d2",
"metadata": {},
"source": [
"# Śledzenie obiektów"
]
},
{
"cell_type": "markdown",
"id": "dbeb1ae1",
"metadata": {},
"source": [
"Załóżmy, że chcemy na poniższym filmie śledzić przemieszczanie się piłkarek:"
]
},
{
"cell_type": "code",
"execution_count": 58,
"id": "7a31e78d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<video src=\"vid/football.mp4\" controls width=\"800\" >\n",
" Your browser does not support the <code>video</code> element.\n",
" </video>"
],
"text/plain": [
"<IPython.core.display.Video object>"
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"IPython.display.Video(\"vid/football.mp4\", width=800)"
]
},
{
"cell_type": "markdown",
"id": "2fc45895",
"metadata": {},
"source": [
"Biblioteka OpenCV posiada [kilka algorytmów](https://docs.opencv.org/4.5.3/dc/d6b/group__tracking__legacy.html) pozwalających na śledzenie obiektów. Poniżej użyjemy algorytmu [*Multiple Instance Learning*](https://docs.opencv.org/4.5.3/d9/dbc/classcv_1_1legacy_1_1TrackerMIL.html):"
]
},
{
"cell_type": "code",
"execution_count": 62,
"id": "a35e3ad7",
"metadata": {},
"outputs": [
{
"ename": "AttributeError",
"evalue": "module 'cv2' has no attribute 'legacy'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_20516\\3721097851.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mbbox\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;36m45\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m350\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m120\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m270\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[0mtracker\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlegacy\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTrackerMIL_create\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 7\u001b[0m \u001b[0mtracker\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mframe\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbbox\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mAttributeError\u001b[0m: module 'cv2' has no attribute 'legacy'"
]
}
],
"source": [
"video = cv.VideoCapture(\"vid/football.mp4\")\n",
"_, frame = video.read()\n",
"\n",
"bbox = (45, 350, 120, 270)\n",
"\n",
"tracker = cv.legacy.TrackerMIL_create()\n",
"tracker.init(frame, bbox)\n",
"\n",
"pt_1 = (int(bbox[0]), int(bbox[1]))\n",
"pt_2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))\n",
"cv.rectangle(frame, pt_1, pt_2, (0, 0, 255), 4, cv.LINE_8)\n",
"\n",
"plt.figure(figsize=(7,7))\n",
"plt.imshow(frame[:,:,::-1]);"
]
},
{
"cell_type": "markdown",
"id": "934dde10",
"metadata": {},
"source": [
"Możemy sprawdzić wyniki pomiędzy poszczególnymi klatkami, jednak tutaj na potrzeby prezentacji dodajmy odstęp co 10 klatek aby można było zauwazyć ruch. Dodatkowo możemy sprawdzić względną prędkość działania algorytmu:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b266b7f9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4.6.0\n"
]
}
],
"source": [
"import cv2 \n",
"print(cv2. __version__) "
]
},
{
"cell_type": "code",
"execution_count": 65,
"id": "4fbe0520",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4.6.0\n"
]
}
],
"source": [
"import cv2 \n",
"print(cv2. __version__) "
]
},
{
"cell_type": "code",
"execution_count": 67,
"id": "b7650ee1",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'tracker' is not defined",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_20516\\4220022586.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[0mtimer\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetTickCount\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mok\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbbox\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtracker\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mframe\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 12\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 13\u001b[0m \u001b[0mfps\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetTickFrequency\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m/\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mcv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetTickCount\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mtimer\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m;\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mNameError\u001b[0m: name 'tracker' is not defined"
]
}
],
"source": [
"count = 50\n",
"\n",
"while count > 0:\n",
"\n",
" ok, frame = video.read()\n",
" if not ok:\n",
" break\n",
"\n",
" timer = cv.getTickCount()\n",
" \n",
" ok, bbox = tracker.update(frame)\n",
" \n",
" fps = cv.getTickFrequency() / (cv.getTickCount() - timer);\n",
"\n",
" if ok:\n",
" pt_1 = (int(bbox[0]), int(bbox[1]))\n",
" pt_2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))\n",
" cv.rectangle(frame, pt_1, pt_2, (0,0,255), 4, cv.LINE_8)\n",
" else :\n",
" cv.putText(frame, \"Tracking failure\", (20, 180), \n",
" cv.FONT_HERSHEY_SIMPLEX, 2, (0,0,255), cv.LINE_AA)\n",
"\n",
" cv.putText(frame, \"FPS : \" + str(int(fps)), (20,50), \n",
" cv.FONT_HERSHEY_SIMPLEX, 2, (0,0,255), cv.LINE_AA)\n",
"\n",
" if count % 10 == 0:\n",
" plt.figure(figsize=(7,7))\n",
" plt.imshow(frame[:,:,::-1])\n",
" count -= 1\n",
"\n",
"video.release()"
]
},
{
"cell_type": "markdown",
"id": "bf17ff66",
"metadata": {},
"source": [
"Istnieje też możliwość jednoczesnego śledzenia kilku obiektów:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d2e56fa9",
"metadata": {},
"outputs": [
{
"ename": "AttributeError",
"evalue": "module 'cv2' has no attribute 'legacy'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32mc:\\Develop\\wmi\\AITECH\\sem2\\wko\\aitech-wko-pub\\wko-07.ipynb Cell 37\u001b[0m in \u001b[0;36m<cell line: 7>\u001b[1;34m()\u001b[0m\n\u001b[0;32m <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X51sZmlsZQ%3D%3D?line=3'>4</a>\u001b[0m bboxes \u001b[39m=\u001b[39m [(\u001b[39m45\u001b[39m, \u001b[39m350\u001b[39m, \u001b[39m120\u001b[39m, \u001b[39m270\u001b[39m), (\u001b[39m755\u001b[39m, \u001b[39m350\u001b[39m, \u001b[39m120\u001b[39m, \u001b[39m270\u001b[39m)]\n\u001b[0;32m <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X51sZmlsZQ%3D%3D?line=4'>5</a>\u001b[0m colors \u001b[39m=\u001b[39m [(\u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m255\u001b[39m), (\u001b[39m0\u001b[39m, \u001b[39m255\u001b[39m, \u001b[39m0\u001b[39m)]\n\u001b[1;32m----> <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X51sZmlsZQ%3D%3D?line=6'>7</a>\u001b[0m multi_tracker \u001b[39m=\u001b[39m cv\u001b[39m.\u001b[39;49mlegacy\u001b[39m.\u001b[39mMultiTracker_create()\n\u001b[0;32m <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X51sZmlsZQ%3D%3D?line=8'>9</a>\u001b[0m \u001b[39mfor\u001b[39;00m bbox \u001b[39min\u001b[39;00m bboxes:\n\u001b[0;32m <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X51sZmlsZQ%3D%3D?line=9'>10</a>\u001b[0m multi_tracker\u001b[39m.\u001b[39madd(cv\u001b[39m.\u001b[39mlegacy\u001b[39m.\u001b[39mTrackerMIL_create(), frame, bbox)\n",
"\u001b[1;31mAttributeError\u001b[0m: module 'cv2' has no attribute 'legacy'"
]
}
],
"source": [
"video = cv.VideoCapture(\"vid/football.mp4\")\n",
"_, frame = video.read()\n",
"\n",
"bboxes = [(45, 350, 120, 270), (755, 350, 120, 270)]\n",
"colors = [(0, 0, 255), (0, 255, 0)]\n",
"\n",
"multi_tracker = cv.legacy.MultiTracker_create()\n",
"\n",
"for bbox in bboxes:\n",
" multi_tracker.add(cv.legacy.TrackerMIL_create(), frame, bbox)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9f989b8a",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'multi_tracker' is not defined",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32mc:\\Develop\\wmi\\AITECH\\sem2\\wko\\aitech-wko-pub\\wko-07.ipynb Cell 38\u001b[0m in \u001b[0;36m<cell line: 3>\u001b[1;34m()\u001b[0m\n\u001b[0;32m <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X52sZmlsZQ%3D%3D?line=6'>7</a>\u001b[0m \u001b[39mbreak\u001b[39;00m\n\u001b[0;32m <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X52sZmlsZQ%3D%3D?line=8'>9</a>\u001b[0m timer \u001b[39m=\u001b[39m cv\u001b[39m.\u001b[39mgetTickCount()\n\u001b[1;32m---> <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X52sZmlsZQ%3D%3D?line=10'>11</a>\u001b[0m _, boxes \u001b[39m=\u001b[39m multi_tracker\u001b[39m.\u001b[39mupdate(frame)\n\u001b[0;32m <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X52sZmlsZQ%3D%3D?line=12'>13</a>\u001b[0m \u001b[39mfor\u001b[39;00m i, bbox \u001b[39min\u001b[39;00m \u001b[39menumerate\u001b[39m(boxes):\n\u001b[0;32m <a href='vscode-notebook-cell:/c%3A/Develop/wmi/AITECH/sem2/wko/aitech-wko-pub/wko-07.ipynb#X52sZmlsZQ%3D%3D?line=13'>14</a>\u001b[0m pt_1 \u001b[39m=\u001b[39m (\u001b[39mint\u001b[39m(bbox[\u001b[39m0\u001b[39m]), \u001b[39mint\u001b[39m(bbox[\u001b[39m1\u001b[39m]))\n",
"\u001b[1;31mNameError\u001b[0m: name 'multi_tracker' is not defined"
]
}
],
"source": [
"count = 50\n",
"\n",
"while count > 0:\n",
"\n",
" ok, frame = video.read()\n",
" if not ok:\n",
" break\n",
"\n",
" timer = cv.getTickCount()\n",
" \n",
" _, boxes = multi_tracker.update(frame)\n",
" \n",
" for i, bbox in enumerate(boxes):\n",
" pt_1 = (int(bbox[0]), int(bbox[1]))\n",
" pt_2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))\n",
" cv.rectangle(frame, pt_1, pt_2, colors[i], 4, cv.LINE_8)\n",
"\n",
" if count % 10 == 0:\n",
" plt.figure(figsize=(7,7))\n",
" plt.imshow(frame[:,:,::-1])\n",
" count -= 1\n",
"\n",
"video.release()"
]
},
{
"cell_type": "markdown",
"id": "b1d84a3a",
"metadata": {},
"source": [
"# Zadanie 1\n",
"\n",
"Dla filmu `vid/football.mp4` porównaj jakość śledzenia dla dostępnych algorytmów. Wyniki zapisz na jednym filmie.\n",
"\n",
"![Porówanie algorytmów śledzenia obiektów](img/football-multi.png)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5df3bd67",
"metadata": {},
"outputs": [],
"source": [
"bbox = (45, 350, 120, 270)\n",
"\n",
"\n",
"def draw_first_rectangle(frame):\n",
" pt_1 = (int(bbox[0]), int(bbox[1]))\n",
" pt_2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))\n",
" cv.rectangle(frame, pt_1, pt_2, (0, 0, 255), 4, cv.LINE_8)\n",
"\n",
" plt.figure(figsize=(7,7))\n",
" plt.imshow(frame[:,:,::-1])\n",
"\n",
"\n",
"def track_object(video, tracker):\n",
"\n",
" count = 50\n",
"\n",
" while count > 0:\n",
"\n",
" ok, frame = video.read()\n",
" if not ok:\n",
" break\n",
"\n",
" timer = cv.getTickCount()\n",
" \n",
" ok, bbox = tracker.update(frame)\n",
" \n",
" fps = cv.getTickFrequency() / (cv.getTickCount() - timer);\n",
"\n",
" if ok:\n",
" pt_1 = (int(bbox[0]), int(bbox[1]))\n",
" pt_2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))\n",
" cv.rectangle(frame, pt_1, pt_2, (0,0,255), 4, cv.LINE_8)\n",
" else :\n",
" cv.putText(frame, \"Tracking failure\", (20, 180), \n",
" cv.FONT_HERSHEY_SIMPLEX, 2, (0,0,255), cv.LINE_AA)\n",
"\n",
" cv.putText(frame, \"FPS : \" + str(int(fps)), (20,50), \n",
" cv.FONT_HERSHEY_SIMPLEX, 2, (0,0,255), cv.LINE_AA)\n",
"\n",
" if count % 10 == 0:\n",
" plt.figure(figsize=(7,7))\n",
" plt.imshow(frame[:,:,::-1])\n",
" count -= 1\n",
"\n",
" video.release()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e647ecf8",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'cv' is not defined",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_20516\\3995343795.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mvideo\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mVideoCapture\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"vid/football.mp4\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2\u001b[0m \u001b[0m_\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mframe\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mvideo\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mtracker\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlegacy\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTrackerMIL_create\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[0mtracker\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mframe\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbbox\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mNameError\u001b[0m: name 'cv' is not defined"
]
}
],
"source": [
"video = cv.VideoCapture(\"vid/football.mp4\")\n",
"_, frame = video.read()\n",
"\n",
"tracker = cv.legacy.TrackerMIL_create()\n",
"tracker.init(frame, bbox)\n",
"\n",
"draw_first_rectangle(frame)\n",
"track_object(video, tracker)"
]
}
],
"metadata": {
"author": "Andrzej Wójtowicz",
"email": "andre@amu.edu.pl",
"kernelspec": {
"display_name": "widzenie_komputerowe",
"language": "python",
"name": "python3"
},
"lang": "pl",
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.12 | packaged by conda-forge | (default, Oct 26 2021, 05:35:01) [MSC v.1916 64 bit (AMD64)]"
},
"subtitle": "07. Analiza wideo [laboratoria]",
"title": "Widzenie komputerowe",
"vscode": {
"interpreter": {
"hash": "6ac7fc53e11b5e853f03d2492fedb08fce658edca143f79fa3d2748d3b63b777"
}
},
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}