Lucas-Kanade稀疏光流法
光流法
光流
由于目標對象或者攝像機的移動造成的圖像對象在連續兩幀圖像中的移動被稱為光流。如下圖所示,它是一個 2D 向量場,可以用來顯示一個點從第一幀圖像到第二幀圖像之間的移動,箭頭表示光流場向量。
其中,光流包括稀疏光流與稠密光流。圖像中的每個像素都使用這種方法,則通常將其稱為“稠密光流”。有一種替代類算法被稱為“稀疏光流”,僅僅跟蹤圖像中某些點的子集。
Lucas-Kanade稀疏光流法
假設先驗
LK光流全稱為Lucas-Kanade光流,算法原理比較好理解,首先,LK光流對應用場景提出了三個假設先驗:
- 亮度恒定:假設像素在運動過程中亮度(灰度值)恒定,其實這是大部分計算機視覺任務都需要的一個先驗。
- 像素偏移小:檢測光流的兩幀之間不能有過大的motion,否則LK光流會檢測失敗。
- 空間一致性:當前幀相鄰的像素在下一幀應該也是相鄰的,這樣便于求解圖像塊的梯度進而尋找到匹配的像素。
算法流程
給定t 時刻的圖像上的像素點I(x,y) ,算法的目標是找到在下一時刻該像素的在各個方向上的位移,用公式表達就是:
I(x,y,t)=I(x+δx,y+δy,t+δt)(1)I ( x , y , t ) = I ( x + \delta x , y + \delta y , t + \delta t ) \tag{1} I(x,y,t)=I(x+δx,y+δy,t+δt)(1)
可以對等號右邊的式子采用泰勒展開:
可以看到等號后邊第一項與等號左邊相等可以消去,?I?x\frac{\partial I}{\partial x}?x?I? 和?I?y\frac{\partial I}{\partial y}?y?I? 比較好理解,就是當前時刻圖像在δxδxδx和δyδyδy方向的梯度了,?I?t\frac{\partial I}{\partial t}?t?I? 表示的的是時間方向上的梯度,也就是下一幀與當前幀的差分。δtδtδt是兩幀時間差也就是1,而δxδxδx和δyδyδy就是我們要求解的像素運動。由此我們可以得到:
Ixδx+Iyδy=?It(3)I _ { x } \delta x + I _ { y } \delta y = - I _ { t }\tag{3} Ix?δx+Iy?δy=?It?(3)
我們現在有兩個未知數但是只有一個方程,無法求解,根據我們在最開始的第三個假設,此時我們可以使用需要求解的像素周圍5×5的像素塊來幫助我們得到更多的方程式:
[Ix1Iy1Ix2Iy2?Ix24Iy24Ix25Iy25][δxδy]=[?It1?It2??It24?It25](4)\left[ \begin{array} { c } { I _ { x 1 } I _ { y 1 } } \\ { I _ { x 2 } I _ { y 2 } } \\ { \cdots } \\ { I _ { x 24 } I _ { y 24 } } \\ { I _ { x 25 } I _ { y 25 } } \end{array} \right] \left[ \begin{array} { c } { \delta x } \\ { \delta y } \end{array} \right] = \left[ \begin{array} { c } { - I _ { t 1 } } \\ { - I _ { t 2 } } \\ { \cdots } \\ { - I _ { t 24 } } \\ { - I _ { t 25 } } \end{array} \right]\tag{4} ???????Ix1?Iy1?Ix2?Iy2??Ix24?Iy24?Ix25?Iy25?????????[δxδy?]=????????It1??It2???It24??It25?????????(4)
此時便組成了一個超定方程組,也就是方程個數大于未知數個數,這是我們可以使用最小二乘法來求解這個方程組。
Ax=?bATAx=AT(?b)(5)\begin{aligned} A x & = - b \\ A ^ { T } A x & = A ^ { T } ( - b ) \\ \end{aligned}\tag{5} AxATAx?=?b=AT(?b)?(5)
方程的解必須滿足以下條件:
-
ATAA ^ { T } AATA 必須可逆
-
ATAA ^ { T } AATA 中的特征值λ1\lambda _ { 1 }λ1?和λ2\lambda _ { 2 }λ2?不能太小。如下圖所示,當特征值過小,說明像素塊選在平緩區域。
-
ATAA ^ { T } AATA 中λ1/λ2\lambda _ { 1 }/\lambda _ { 2 }λ1?/λ2?不能太大。如下圖所示,當λ1/λ2\lambda _ { 1 }/\lambda _ { 2 }λ1?/λ2?過大時,說明素塊選在邊緣區域。
總結
像素塊不能選在平緩區域和邊緣區域。如下圖所示,像素塊最好選在紋理豐富的區域。
LK光流法存在的問題
在實際的拍攝的視頻中,每一幀不一定都滿足三個假設:亮度恒定、像素偏移小和空間一致性。
-
亮度恒定不滿足,
解決方法:梯度恒定
-
像素偏移過大
解決方法:采樣高斯金字塔方法,估計光流
-
像素塊不滿足空間一致性。
代碼實現:
import numpy as np import cv2cap = cv2.VideoCapture("768x576.avi")# ShiTomas角點檢測的參數 feature_params = dict(maxCorners =100,qualityLevel=0.3,minDistance=7,blockSize=7)# 金字塔LK算法參數 lk_params = dict(winSize=(15,15),maxLevel=2,criteria=(cv2.TERM_CRITERIA_EPS|cv2.TermCriteria_COUNT,10,0.03)) # 創建隨機顏色 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 = np.zeros_like(old_frame)while(1):ret,frame = cap.read()if ret is True: frame_gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)else: breakp1,st,err = cv2.calcOpticalFlowPyrLK(old_gray,frame_gray,p0,None,**lk_params)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(30)&0xffif k == 27:breakold_gray = frame_gray.copy()p0 = good_new.reshape(-1,1,2)cv2.destroyAllWindows() cap.release()結果:
參考文獻:
[1] B. Lucas and T. Kanade, “An iterative image registration technique with an
application to stereo vision,” in Proc. of International Joint Conf. On Artificial
Intelligence, pp.674-679, 1981.
[2] 浙江大學陸系群教授,《Motion Estimation Optical Flow.PPT》
[3] 《OpenCV-Python 中文教程》
[4]LK稀疏光流法
總結
以上是生活随笔為你收集整理的Lucas-Kanade稀疏光流法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA代码各种效果的素材网
- 下一篇: Excel中插入函数工具的使用技巧