在上一篇文章中,我們簡(jiǎn)單了解一下光流法的原理.
在這一篇文章中,我們使用OpenCV中的calcOpticalFlowPyrLK()函數(shù)來(lái)實(shí)現(xiàn),是基于金字塔LK光流算法爹袁,計(jì)算某些點(diǎn)集的稀疏光流。
這個(gè)函數(shù)的具體介紹在
這個(gè)網(wǎng)址有很詳細(xì)的介紹,一些具體的參數(shù)需要去這個(gè)網(wǎng)站上看一下.
在接下來(lái),我們來(lái)看一下在OpenCV中l(wèi)k算法的實(shí)現(xiàn).
代碼的路徑在opencv\sources\samples\python\lk_track.py
代碼本身有英文的注釋,我一起把注釋翻譯成中文,捋順以后發(fā)現(xiàn)原理還是很好理解.
import numpy as np
import cv2 as cv
cap = cv.VideoCapture("test.avi")
# params for ShiTomasi corner detection 設(shè)置 ShiTomasi 角點(diǎn)檢測(cè)的參數(shù)
feature_params = dict(maxCorners=100,
? ? ? ? ? ? ? ? ? ? ? qualityLevel=0.3,
? ? ? ? ? ? ? ? ? ? ? minDistance=7,
? ? ? ? ? ? ? ? ? ? ? blockSize=7)
# Parameters for lucas kanade optical flow 設(shè)置 lucas kanade 光流場(chǎng)的參數(shù)
# maxLevel 為使用的圖像金字塔層數(shù)
lk_params = dict(winSize=(15, 15),
? ? ? ? ? ? ? ? maxLevel=2,
? ? ? ? ? ? ? ? criteria=(cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
# Create some random colors 產(chǎn)生隨機(jī)的顏色值
color = np.random.randint(0, 255, (100, 3))
# Take first frame and find corners in it 獲取第一幀耘沼,并尋找其中的角點(diǎn)
(ret, old_frame) = cap.read()
old_gray = cv.cvtColor(old_frame, cv.COLOR_BGR2GRAY)
p0 = cv.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
# Create a mask image for drawing purposes 創(chuàng)建一個(gè)掩膜為了后面繪制角點(diǎn)的光流軌跡
mask = np.zeros_like(old_frame)
# 視頻文件輸出參數(shù)設(shè)置
out_fps = 12.0? # 輸出文件的幀率
fourcc = cv.VideoWriter_fourcc('M', 'P', '4', '2')
sizes = (int(cap.get(cv.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv.CAP_PROP_FRAME_HEIGHT)))
out = cv.VideoWriter('E:/video/v5.avi', fourcc, out_fps, sizes)
while True:
? ? (ret, frame) = cap.read()
? ? frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
? ? # calculate optical flow 能夠獲取點(diǎn)的新位置
? ? p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
? ? # Select good points 取好的角點(diǎn)豪硅,并篩選出舊的角點(diǎn)對(duì)應(yīng)的新的角點(diǎn)
? ? good_new = p1[st == 1]
? ? good_old = p0[st == 1]
? ? # draw the tracks 繪制角點(diǎn)的軌跡
? ? for i, (new, old) in enumerate(zip(good_new, good_old)):
? ? ? ? a, b = new.ravel()
? ? ? ? c, d = old.ravel()
? ? ? ? mask = cv.line(mask, (a, b), (c, d), color[i].tolist(), 2)
? ? ? ? frame = cv.circle(frame, (a, b), 5, color[i].tolist(), -1)
? ? img = cv.add(frame, mask)
? ? cv.imshow('frame', img)
? ? out.write(img)
? ? k = cv.waitKey(200) & 0xff
? ? if k == 27:
? ? ? ? break
? ? # Now update the previous frame and previous points 更新當(dāng)前幀和當(dāng)前角點(diǎn)的位置
? ? old_gray = frame_gray.copy()
? ? p0 = good_new.reshape(-1, 1, 2)
out.release()
cv.destroyAllWindows()
cap.release()
運(yùn)行之后的結(jié)果:
可以看到這個(gè)算法實(shí)現(xiàn)起來(lái)效果很差,不過(guò)沒(méi)關(guān)系,到后來(lái)一步一步我們的算法會(huì)變得很優(yōu)秀,追蹤的效率也會(huì)很順暢.大家亦可以改改里邊的參數(shù),發(fā)現(xiàn)效果還是有很大的不一樣.
最后,有關(guān)LK光流法,推薦看一看這一篇論文《Pyramidal Implementation of the Lucas Kanade Feature TrackerDescription of the algorithm》,會(huì)有更大的收獲.