1.cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params) 用於獲得光流估計所需要的角點
參數說明:old_gray表示輸入圖片,mask表示掩模,feature_params:maxCorners=100角點的最大個數,qualityLevel=0.3角點品質,minDistance=7即在這個范圍內只存在一個品質最好的角點
2. pl, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params) 用於獲得光流檢測后的角點位置
參數說明:pl表示光流檢測后的角點位置,st表示是否是運動的角點,err表示是否出錯,old_gray表示輸入前一幀圖片,frame_gray表示后一幀圖片,p0表示需要檢測的角點,lk_params:winSize表示選擇多少個點進行u和v的求解,maxLevel表示空間金字塔的層數
3. cv2.add(frame, mask) # 將兩個圖像的像素進行加和操作
參數說明:frame表示輸入圖片,mask表示掩模
光流估計:通過當前時刻與前一時刻的亮度不變的特性I(x, y, t) = I(x+∆x, y+∆y, t+∆t) 使用lucas-kanade算法進行求解問題, 我們需要求得的是x,y方向的速度
下面是lucas-kanade的推導公式, 即位置發生變動時,其像素點的大小沒有發生變化,
I(x, y, t) = I(x+dx, y+dy, t+dt)
= I(x, y, t) + Ixdx + Iydy + Itdt 使用泰勒基數進行展開
對上式進行化解即:
Ixdx + Iydy + Itdt = 0 Ix表示x軸的梯度方向,Iy表示y軸的梯度方向,It表示單位時間上的像素點的變化
如果我們使用前后兩幀的變化, 那么dx和dy也就是表示x軸和y軸的速度,返回的結果是dx和dy,即在x軸和y軸方向上移動的步數,我們就可以知道目標的位置了
下面是實際求解u和v的過程,根據上述的空間一致性,我們選擇出關鍵點周圍的25個點進行求解,即(5, 5)的方框, 構造Au = b 進行求解,我們可以看出(A^T*A)^-1
但是當前像素點不一定可逆,如果保證可逆呢,即A^T*A的特征值λ1和λ2接近相等且較大,符合條件的就是角點, 因此使用角點去求解u和v
代碼:
第一步:使用cv2.capture讀入視頻
第二步:構造角點檢測所需參數, 構造lucas kanade參數
第三步:拿到第一幀圖像,並做灰度化, 作為光流檢測的前一幀圖像
第四步:使用cv2.goodFeaturesToTrack獲得光流檢測所需要的角點
第五步:構造一個mask用於畫直線
第六步:讀取一張圖片,進行灰度化,作為光流檢測的后一幀圖像
第七步:使用cv2.caclOpticalFlowPyrLK進行光流檢測
第八步:使用st==1獲得運動后的角點,原始的角點位置
第九步:循環獲得角點的位置,在mask圖上畫line,在后一幀圖像上畫角點
第十步:使用cv2.add()將mask和frame的像素點相加並進行展示
第十一步:使用后一幀的圖像更新前一幀的圖像,同時使用運動的后一幀的角點位置來代替光流檢測需要的角點
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) # 第四步:返回所有檢測特征點,需要輸入圖片,角點的最大數量,品質因子,minDistance=7如果這個角點里有比這個強的就不要這個弱的 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) # 第七步:進行光流檢測需要輸入前一幀和當前圖像及前一幀檢測到的角點 pl, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params) # 第八步:讀取運動了的角點st == 1表示檢測到的運動物體,即v和u表示為0 good_new = pl[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) # p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params) cv2.destroyAllWindows() cap.release()