因為研究需要,仔細看了下代碼,看看有什麼可以利用的地方。
整體來說Kanade-Lucas-Tomasi Feature Tracker的方法就是首先找去特徵點,之後用光流去跟蹤的方法。
Opencv中已經有了example,大家可以運行下看效果,同時Homepage:http://www.ces.clemson.edu/~stb/klt/
上有源碼,整個的流程跟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三個值的修改。
不對的地方請大家指正。