2012-07-27 6 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에서만 작동한다는 것을 알아 냈습니다. 이동하는 사각형에서 원점에서 얼마나 멀리 떨어져 있는지 확인하려고했습니다. 네 모서리를 거의 감지하지 못합니다. 루카스 - Kanade의

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; 
     } 
    } 

} 

OpenCV의 구현은 바이너리 이미지에 사각형을 추적 할 수없는 것 같다. 잘못되었거나이 기능이 작동하지 않습니까?

답변

2

KLT는 특정 창과 관련된 두 세트의 점 사이의 변환을 찾아 점 추적을합니다. 창 크기는 다른 프레임에서 일치시키기 위해 각 지점을 쫓는 영역입니다.

추적 할 좋은 기능을 찾는 그라데이션을 기반으로 한 또 다른 알고리즘입니다.

일반적으로 KLT는 큰 움직임에서도 추적을 유지하기 위해 피라미드 방식을 사용합니다. 그것은 당신이 지정한 "창 크기"에 대해 "maxLevel"시간에 사용합니다.

이진 이미지에서 KLT를 사용해 본 적이 없습니다. 문제는 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 크기까지 테스트 해왔다. 그 값들 중 어느 것도 1 점조차도 발견하지 못했습니다. –

+0

글쎄, 그건 정상적인 행동이 아니야. 나는 개인적으로 openCV를 사용하기 위해 장애물을 가지고 있었지만, 나는 그것을 정말로 똑바로 찾고 예제/문서를 찾지 못했다. ViSP (GPL) [ViSP 웹 사이트] (http://www.irisa.fr/lagadic/visp/visp.html)에 시도해 볼 수 있습니다. KLT로 도트 추적에 대한 자습서가 있습니다. – StackHola

8

Lucas Kanade 메서드는 해당 영역의 그라디언트를 사용하여 영역의 동작을 추정합니다. 그라디언트가 메소드를 강습하는 경우입니다. 그래서 x와 y 방향으로 그라데이션이 없으면 메서드가 실패합니다. 두 번째 중요한 점은 루카스 Kanade 방정식

E = sum_ {winsize}이 (IX * U + 리딕 * V * IT) ²

이 강도 유지율의 구속의 일차 테일러 근사하다.

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

그래서 레벨없이 방법의 제한 (화상 피라미드) 화상이 될 필요가 있다는 것이다 선형 함수. 실제로 이것은 작은 동작을 의미 할 수 있습니다. 이는 선택한 winsize에 따라 달라질 수 있습니다. 그게 왜 이미지를 선형화하는 레벨을 사용하는지 (It). 그래서 5 레벨이 조금 높을 것입니다. 3 충분해야합니다. 최고 수준의 이미지가 경우의 크기가 640 × 480/2^5 × 15

마지막 코드에서 문제가 라인 = 20 :

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

는 루카스에서 돌아 오기 오류가 kanade 방법은 다음을 의미하는 결과 SSD입니다.

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

오류가 0 일 가능성은 매우 낮습니다. 결국 모든 기능을 건너 뜁니다. 나는 오류를 무시함으로써 좋은 경험을했습니다, 그것은 단지 자신감의 척도입니다. Foreward/Backward 신뢰도와 같은 매우 좋은 대체 신뢰도 측정 방법이 있습니다. 너무 많은 물질이 폐기되면 상태 플래그를 무시하여 실험을 시작할 수도 있습니다.