1. 程式人生 > >光流(四)--Kanade-Lucas-Tomasi(KLT)目標跟蹤

光流(四)--Kanade-Lucas-Tomasi(KLT)目標跟蹤

原文:

http://www.cnblogs.com/moondark/archive/2012/05/12/2497391.html

近來在研究跟蹤,跟蹤的方法其實有很多,如粒子濾波(pf)、meanshift跟蹤,以及KLT跟蹤或叫Lucas光流法,這些方法各自有各自的有點,對於粒子濾波而言,它能夠比較好的在全域性搜尋到最優解,但其求解速度相對較慢,由於其是基於顏色直方圖的計算,所以對相同顏色東西不太能夠區別,meanshift方法很容易陷入區域性最優,但速度還是挺快,所以現在很有一些人是將meanshift跟pf結合做跟蹤,恰好在很多方面能夠互補。

  Kanade-Lucas-Tomasi方法,在跟蹤方面表現的也不錯,尤其在實時計算速度上,用它來得到的,是很多點的軌跡“trajectory”,並且還有一些發生了漂移的點,所以,得到跟蹤點之後要進行一些後期的處理,說到Kanade-Lucas-Tomasi方法,首先要追溯到Kanade-Lucas兩人在上世紀80年代發表的paper:An Iterative Image Registration Technique with an Application to Stereo Vision,這裡講的是一種影象點定位的方法,即影象的區域性匹配,將影象匹配問題,從傳統的滑動視窗搜尋方法變為一個求解偏移量d的過程,後來Jianbo Shi和Carlo Tomasi兩人發表了一篇CVPR(94')的文章Good Features To Track,這篇文章,主要就是講,在求解d的過程中,哪些情況下可以保證一定能夠得到d的解,這些情況的點有什麼特點(後來會發現,很多時候都是尋找的角點)。

  PS: 其實我很奇怪這個演算法為什麼叫做KLT演算法,而不加上Jianbo Shi的名字~

  好吧,前戲就這麼多,接下來進入正題,KLT是如何實現跟蹤的?

  先說KLT演算法的幾個前提假設:
   1)亮度恆定
   2)時間連續或者是運動是“小運動”
     3)空間一致,臨近點有相似運動,保持相鄰

  這幾個為什麼要這麼假設,我在後面來解釋,很直觀的講,如果判斷一個視訊的相鄰兩幀I、J在某區域性視窗w上是一樣的,則在視窗w內有:I(x, y, t) = J(x', y', t+τ),亮度恆定的假設(假設1)即為了保證其等號成立不受亮度的影響,假設2是為了保證KLT能夠找到點,假設3則為以下原因假設(即對於同一個視窗中,所有點的偏移量都相等):

  在視窗w上,所有(x, y)都往一個方向移動了(dx,  dy),從而得到(x', y'),即t時刻的(x, y)點在t+τ時刻為(x+dx, y+dy),所以尋求匹配的問題可化為對以下的式子尋求最小值,或叫做最小化以下式子:

  用積分來表示上述式子,以上式子可等效為:

  這個式子的含義,即找到兩副影象中,在W視窗中,I、J的差異,其中I以x-d/2為中心,J以x+d/2為中心,w/2為半徑的一個矩形視窗間的差異,好吧,結合我們微積分的知識,函式ε(d)要取得最小值,這個極值點的導數一定為0,即
  

的值為0,由泰勒展開的性質:

可以得到:

於是,問題轉化為:

其中:

從而,問題即為:

=>

即其等式可看作為:

其中,Z為一個2*2的矩陣,e為一個2*1的向量,

為了要使d能夠得到解,則Z需要滿足條件,即Z*Z'矩陣可逆,其中Z'為Z矩陣的轉置(ZT),在一般情況下,角點具有這樣的特點。

在OpenCV裡面,找角點的函式可用

複製程式碼
void cvGoodFeaturesToTrack(
   const CvArr* image
   CvArr* eigImage, CvArr* tempImage
   CvPoint2D32f* corners
   int* cornerCount
   double qualityLevel
   double minDistance
   const CvArr* mask=NULL
   int blockSize=3
   int useHarris=0 //一般採用Harris角點
   double k=0.04 );
複製程式碼

然後可以通過函式cvCalcOpticalFlowPyrLK進行跟蹤(好像OpenCV裡面呼叫LK的函式不止這一個,這個是金字塔計算):

複製程式碼
void cvCalcOpticalFlowPyrLK(
    const CvArr* prev,
    const CvArr* curr,
    CvArr* prevPyr,
    CvArr* currPyr,
    const CvPoint2D32f* prevFeatures,
    CvPoint2D32f* currFeatures,
    int count,
    CvSize winSize,
    int level,
    char* status,
    float* track error,
    CvTermCriteria criteria,
    int flags );
複製程式碼

  OK,KLT演算法的原理基本就這樣,其實其跟蹤效果並非太準,後來有很多提出的校正的方法,其中我目前看到比較實用的就是TLD演算法的作者Zdenek Kalal在他2010年ICPR上的文章Forward-Backward Error: Automatic Detection of Tracking Failures提出的方法看起來非常不錯,我正動手實現之。