2012-07-27 48 views
2

我在Linux上使用OpenCV 2.4.2。我用C++編寫。我想跟蹤簡單的物體(例如白色背景上的黑色矩形)。首先,我使用goodFeaturesToTrack,然後使用calcOpticalFlowPyrLK在另一圖像上查找這些點。問題是calcOpticalFlowPyrLK沒有找到這些點。OpenCV 2.4.2 calcOpticalFlowPyrLK沒有找到任何點

我發現代碼,不會在C,這並不在我的情況下工作:http://dasl.mem.drexel.edu/~noahKuntz/openCVTut9.html

我已經把它轉換成C++:

int main(int, char**) { 
    Mat imgAgray = imread("ImageA.png", CV_LOAD_IMAGE_GRAYSCALE); 
    Mat imgBgray = imread("ImageB.png", CV_LOAD_IMAGE_GRAYSCALE); 
    Mat imgC = imread("ImageC.png", CV_LOAD_IMAGE_UNCHANGED); 

    vector<Point2f> cornersA; 

    goodFeaturesToTrack(imgAgray, cornersA, 30, 0.01, 30); 

    for (unsigned int i = 0; i < cornersA.size(); i++) { 
     drawPixel(cornersA[i], &imgC, 2, blue); 
    } 

    // I have no idea what does it do 
// cornerSubPix(imgAgray, cornersA, Size(15, 15), Size(-1, -1), 
//   TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 20, 0.03)); 

    vector<Point2f> cornersB; 
    vector<uchar> status; 
    vector<float> error; 

    // winsize has to be 11 or 13, otherwise nothing is found 
    int winsize = 11; 
    int maxlvl = 5; 

    calcOpticalFlowPyrLK(imgAgray, imgBgray, cornersA, cornersB, status, error, 
      Size(winsize, winsize), maxlvl); 

    for (unsigned int i = 0; i < cornersB.size(); i++) { 
     if (status[i] == 0 || error[i] > 0) { 
      drawPixel(cornersB[i], &imgC, 2, red); 
      continue; 
     } 
     drawPixel(cornersB[i], &imgC, 2, green); 
     line(imgC, cornersA[i], cornersB[i], Scalar(255, 0, 0)); 
    } 

    namedWindow("window", 1); 
    moveWindow("window", 50, 50); 
    imshow("window", imgC); 

    cvWaitKey(0); 

    return 0; 
} 

ImageA:http://oi50.tinypic.com/14kv05v.jpg

ImageB:http://oi46.tinypic.com/4l3xom.jpg

ImageC:http://oi47.tinypic.com/35n3uox.jpg

我發現它只適用於winsize = 11。我試圖在移動的矩形上使用它來檢查它離原點的距離。它幾乎沒有檢測到所有四個角落。

int main(int, char**) { 
    std::cout << "Compiled at " << __TIME__ << std::endl; 

    Scalar white = Scalar(255, 255, 255); 
    Scalar black = Scalar(0, 0, 0); 
    Scalar red = Scalar(0, 0, 255); 
    Rect rect = Rect(50, 100, 100, 150); 

    Mat org = Mat(Size(640, 480), CV_8UC1, white); 
    rectangle(org, rect, black, -1, 0, 0); 

    vector<Point2f> features; 
    goodFeaturesToTrack(org, features, 30, 0.01, 30); 
    std::cout << "POINTS FOUND:" << std::endl; 
    for (unsigned int i = 0; i < features.size(); i++) { 
     std::cout << "Point found: " << features[i].x; 
     std::cout << " " << features[i].y << std::endl; 
    } 

    bool goRight = 1; 

    while (1) { 

     if (goRight) { 
      rect.x += 30; 
      rect.y += 30; 
      if (rect.x >= 250) { 
       goRight = 0; 
      } 
     } else { 
      rect.x -= 30; 
      rect.y -= 30; 
      if (rect.x <= 50) { 
       goRight = 1; 
      } 
     } 

     Mat frame = Mat(Size(640, 480), CV_8UC1, white); 
     rectangle(frame, rect, black, -1, 0, 0); 

     vector<Point2f> found; 
     vector<uchar> status; 
     vector<float> error; 
     calcOpticalFlowPyrLK(org, frame, features, found, status, error, 
        Size(11, 11), 5); 

     Mat display; 
     cvtColor(frame, display, CV_GRAY2BGR); 

     for (unsigned int i = 0; i < found.size(); i++) { 
      if (status[i] == 0 || error[i] > 0) { 
       continue; 
      } else { 
       line(display, features[i], found[i], red); 
      } 
     } 

     namedWindow("window", 1); 
     moveWindow("window", 50, 50); 
     imshow("window", display); 

     if (cvWaitKey(300) > 0) { 
      break; 
     } 
    } 

} 

Lucas-Kanade的OpenCV實現似乎無法跟蹤二進制圖像上的矩形。我做錯了什麼或者這個功能不起作用?

回答

2

KLT通過查找關於某個窗口的兩組點之間的轉換來進行點跟蹤。窗口大小是每個點將被追趕以便在其他幀上匹配它的區域。

這是另一種基於漸變的算法,可以找到跟蹤的好特徵。

正常情況下,即使大動作,康萊特仍然採用金字塔方式來保持跟蹤。它可能在「maxLevel」時間用於指定的「窗口大小」。

從未在二進制圖像上試過KLT。問題可能出在康萊德的實施上,開始朝着錯誤的方向進行搜索,然後失去了重點。當你改變窗口大小時,搜索算法也會改變。在你的照片上,你最多隻有4個興趣點,只有1個像素。

這些參數你有興趣:

winSize – Size of the search window at each pyramid level 
maxLevel – 0-based maximal pyramid level number. If 0, pyramids are not used (single level), if 1, two levels are used etc. 
criteria – Specifies the termination criteria of the iterative search algorithm (after the specified maximum number of iterations criteria.maxCount or when the search window moves by less than criteria.epsilon 

建議:

  • 你嘗試與自然的照片? (例如兩張照片),您將擁有更多功能來跟蹤。 4或更少是很難保持。我會嘗試這第一
+0

是的,我嘗試過使用自然圖片。我一直在測試它的窗口大小高達150和最高水平高達100上百張圖像。對於任何這些值,它甚至沒有檢測到一點。 – 2012-07-30 08:37:01

+0

好吧,那肯定不是一個正常的行爲。我個人在使用openCV時遇到了一些障礙,我並沒有發現它非常簡單,並且示例/文檔非常有幫助。您可能想嘗試一下ViSP(在GPL下)[ViSP網站](http://www.irisa.fr/lagadic/visp/visp.html) 有一本關於使用康萊特提供點跟蹤的教程 – StackHola 2012-07-31 08:04:47

8

盧卡斯卡納德方法通過使用該地區的梯度估計區域的運動。在某種情況下,漸變會降低方法。所以如果你在x和y方向沒有漸變,那麼這個方法就會失敗。第二個重要的值得注意的是,盧卡斯奏方程

E = {sum_}使用winsize(九* U + IY * V *它)²

是強度恆定約束的一階泰勒近似。

I(X,Y,T)= I(X + U,Y + V,T + 1)

因此該方法的無電平的限制(圖像金字塔)是圖像需要是一個線性函數。在實踐中,這意味着只有很小的動作可以估計,取決於你選擇的勝利。這就是爲什麼你使用水平線性圖像(It)。所以5的水平是有點高3應該是足夠的。你的情況頂層圖像具有尺寸640×480/2^5 = 20×15

最後,在你的代碼的問題是線路:

if (status[i] == 0 || error[i] > 0) { 

您從盧卡斯找回錯誤kanade方法是由此產生的SSD,即:

error = sum(winSize)(I(x,y,0) - I(x + u,y + u,1)^ 2)/(winsize * winsize)

這是不太可能的,錯誤是0.所以最後你跳過所有功能。我忽略錯誤有很好的經驗,這只是一種信心措施。作爲向前/向後的信心,有很好的替代信心措施。您也可以通過忽略狀態標誌開始實驗,如果過多的缺陷被丟棄