1. 程式人生 > >Kanade-Lucas-Tomasi Feature Tracker 程式碼分析

Kanade-Lucas-Tomasi Feature Tracker 程式碼分析

因為研究需要,仔細看了下程式碼,看看有什麼可以利用的地方。

整體來說Kanade-Lucas-Tomasi Feature Tracker的方法就是首先找去特徵點,之後用光流去跟蹤的方法。

上有原始碼,整個的流程跟Opencv差不多。

我們以官網上的原程式中的example1進行分析:(剩下的幾個例子整體流程都差不多,僅僅是目的不一樣)

首先都是建立兩個結構體:

  tc = KLTCreateTrackingContext();
  KLTPrintTrackingContext(tc);
  fl = KLTCreateFeatureList(nFeatures);

tc就是跟蹤的中用到的一些引數在選特徵點的時候也有用到。

fl就是我們說道德特徵點了,包括了特徵值和特徵點在影象中的位置。

之後使用:

KLTSelectGoodFeatures(tc, img1, ncols, nrows, fl);

使用上面的函式選取特徵點

KLTTrackFeatures(tc, img1, img2, ncols, nrows, fl);

使用這個函式在img2中尋找對應的特徵點。

一次迴圈就可以實現跟蹤了。

那麼出現了一個問題:特徵點是怎麼定義的:

我們分析KLTSelectGoodFeatures這個函式:

函式中又使用了:

_KLTSelectGoodFeatures(tc, img, ncols, nrows, 
                         fl, SELECTING_ALL);


這個函式,函式中首先見了了一個pointlist的分量,並分配了記憶體空間:

 pointlist = (int *) malloc(ncols * nrows * 3 * sizeof(int));

為什麼要*3呢?其實pointlist中存了影象中點的位置x,y和特徵值的大小val。

特徵值是什麼呢?這個特徵是就是對應畫素點的梯度值。

{
    register float gx, gy;
    register float gxx, gxy, gyy;
    register int xx, yy;
    register int *ptr;
    float val;
    unsigned int limit = 1;
    int borderx = tc->borderx;	/* Must not touch cols */
    int bordery = tc->bordery;	/* lost by convolution */
    int x, y;
    int i;
	
    if (borderx < window_hw)  borderx = window_hw;
    if (bordery < window_hh)  bordery = window_hh;

    /* Find largest value of an int */
    for (i = 0 ; i < sizeof(int) ; i++)  limit *= 256;
    limit = limit/2 - 1;
		
    /* For most of the pixels in the image, do ... */
    ptr = pointlist;
    for (y = bordery ; y < nrows - bordery ; y += tc->nSkippedPixels + 1)
      for (x = borderx ; x < ncols - borderx ; x += tc->nSkippedPixels + 1)  {

        /* Sum the gradients in the surrounding window */
        gxx = 0;  gxy = 0;  gyy = 0;
        for (yy = y-window_hh ; yy <= y+window_hh ; yy++)
          for (xx = x-window_hw ; xx <= x+window_hw ; xx++)  {
            gx = *(gradx->data + ncols*yy+xx);
            gy = *(grady->data + ncols*yy+xx);
            gxx += gx * gx;
            gxy += gx * gy;
            gyy += gy * gy;
          }

        /* Store the trackability of the pixel as the minimum
           of the two eigenvalues */
        *ptr++ = x;
        *ptr++ = y;
        val = _minEigenvalue(gxx, gxy, gyy);
        if (val > limit)  {
          KLTWarning("(_KLTSelectGoodFeatures) minimum eigenvalue %f is "
                     "greater than the capacity of an int; setting "
                     "to maximum value", val);
          val = (float) limit;
        }
        *ptr++ = (int) val;
        npoints++;
      }

程式碼中的特徵值取得時每個畫素點臨域梯度值的加權值。

之後程式來到了函式:

 _enforceMinimumDistance(
    pointlist,
    npoints,
    featurelist,
    ncols, nrows,
    tc->mindist,
    tc->min_eigenvalue,
    overwriteAllFeatures);

這裡通過比較每個畫素點val和對應閾值的大小來提取特徵點:

if (!featuremap[y*ncols+x] && val >= min_eigenvalue)  {
      featurelist->feature[indx]->x   = (KLT_locType) x;
      featurelist->feature[indx]->y   = (KLT_locType) y;
      featurelist->feature[indx]->val = (int) val;
      featurelist->feature[indx]->aff_img = NULL;
      featurelist->feature[indx]->aff_img_gradx = NULL;
      featurelist->feature[indx]->aff_img_grady = NULL;
      featurelist->feature[indx]->aff_x = -1.0;
      featurelist->feature[indx]->aff_y = -1.0;
      featurelist->feature[indx]->aff_Axx = 1.0;
      featurelist->feature[indx]->aff_Ayx = 0.0;
      featurelist->feature[indx]->aff_Axy = 0.0;
      featurelist->feature[indx]->aff_Ayy = 1.0;
      indx++;

min_eigenvalue就是所使用的閾值,在tc中定義

那麼程式的修改,我們需要根據自己的特徵對這個閾值進行修改,同時對featurelist進行如上的修改,其實主要還是x,y,val三個值的修改。

不對的地方請大家指正。