光流估計
光流是空間運動物體在觀測成像平面上的像素運動的“瞬時速度”,根據各個像素點的速度矢量特征,可以對圖像進行動態分析,例如目標跟蹤。
- 亮度恆定:同一點隨着時間的變化,其亮度不會發生改變。
- 小運動:隨着時間的變化不會引起位置的劇烈變化,只有小運動情況下才能用前后幀之間單位位置變化引起的灰度變化去近似灰度對位置的偏導數。
- 空間一致:一個場景上鄰近的點投影到圖像上也是鄰近點,且鄰近點速度一致。因為光流法基本方程約束只有一個,而要求x,y方向的速度,有兩個未知變量。所以需要連立n多個方程求解。
Lucas-Kanade 算法
如何求解方程組呢?看起來一個像素點根本不夠,在物體移動過程中還有哪些特性呢?
cv2.calcOpticalFlowPyrLK()
參數:
- prevImage 前一幀圖像
- nextImage 當前幀圖像
- prevPts 待跟蹤的特征點向量
- winSize 搜索窗口的大小
- maxLevel 最大的金字塔層數
返回:
- nextPts 輸出跟蹤特征點向量
- status 特征點是否找到,找到的狀態為1,未找到的狀態為0
import numpy as np import cv2 cap = cv2.VideoCapture('test.avi') # 角點檢測所需參數 feature_params = dict( maxCorners = 100, qualityLevel = 0.3, minDistance = 7) # lucas kanade參數 lk_params = dict( winSize = (15,15), maxLevel = 2) # 隨機顏色條 color = np.random.randint(0,255,(100,3)) # 拿到第一幀圖像 ret, old_frame = cap.read() old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY) # 返回所有檢測特征點,需要輸入圖像,角點最大數量(效率),品質因子(特征值越大的越好,來篩選) # 距離相當於這區間有比這個角點強的,就不要這個弱的了 p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params) # 創建一個mask mask = np.zeros_like(old_frame) while(True): ret,frame = cap.read() frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 需要傳入前一幀和當前圖像以及前一幀檢測到的角點 p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params) # st=1表示 good_new = p1[st==1] good_old = p0[st==1] # 繪制軌跡 for i,(new,old) in enumerate(zip(good_new,good_old)): a,b = new.ravel() c,d = old.ravel() mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2) frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1) img = cv2.add(frame,mask) cv2.imshow('frame',img) k = cv2.waitKey(150) & 0xff if k == 27: break # 更新 old_gray = frame_gray.copy() p0 = good_new.reshape(-1,1,2) cv2.destroyAllWindows() cap.release()
效果: