596 lines
17 KiB
Plaintext
596 lines
17 KiB
Plaintext
|
{
|
|||
|
"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": null,
|
|||
|
"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": null,
|
|||
|
"id": "1629fc29",
|
|||
|
"metadata": {},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"IPython.display.Video(\"vid/bike.mp4\", width=800)"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"id": "aa176c9a",
|
|||
|
"metadata": {},
|
|||
|
"source": [
|
|||
|
"Załadujmy film:"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": null,
|
|||
|
"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": null,
|
|||
|
"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 Lucasa–Kanade, 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": null,
|
|||
|
"id": "14b62820",
|
|||
|
"metadata": {},
|
|||
|
"outputs": [],
|
|||
|
"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": null,
|
|||
|
"id": "d8686953",
|
|||
|
"metadata": {},
|
|||
|
"outputs": [],
|
|||
|
"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": null,
|
|||
|
"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": null,
|
|||
|
"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": null,
|
|||
|
"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": null,
|
|||
|
"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": null,
|
|||
|
"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": null,
|
|||
|
"id": "4b58bce1",
|
|||
|
"metadata": {},
|
|||
|
"outputs": [],
|
|||
|
"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": null,
|
|||
|
"id": "041e29a5",
|
|||
|
"metadata": {},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"IPython.display.Video(\"vid/gen-protest.mp4\", width=800)"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"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": null,
|
|||
|
"id": "7a31e78d",
|
|||
|
"metadata": {},
|
|||
|
"outputs": [],
|
|||
|
"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": null,
|
|||
|
"id": "a35e3ad7",
|
|||
|
"metadata": {},
|
|||
|
"outputs": [],
|
|||
|
"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": "b7650ee1",
|
|||
|
"metadata": {},
|
|||
|
"outputs": [],
|
|||
|
"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": [],
|
|||
|
"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": [],
|
|||
|
"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)"
|
|||
|
]
|
|||
|
}
|
|||
|
],
|
|||
|
"metadata": {
|
|||
|
"author": "Andrzej Wójtowicz",
|
|||
|
"email": "andre@amu.edu.pl",
|
|||
|
"kernelspec": {
|
|||
|
"display_name": "Python 3",
|
|||
|
"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.3"
|
|||
|
},
|
|||
|
"subtitle": "07. Analiza wideo [laboratoria]",
|
|||
|
"title": "Widzenie komputerowe",
|
|||
|
"year": "2021"
|
|||
|
},
|
|||
|
"nbformat": 4,
|
|||
|
"nbformat_minor": 5
|
|||
|
}
|