简体   繁体   English

OpenCV 2.4.2 calcOpticalFlowPyrLK找不到任何积分

[英]OpenCV 2.4.2 calcOpticalFlowPyrLK doesn't find any points

I am using OpenCV 2.4.2 on Linux. 我在Linux上使用OpenCV 2.4.2。 I am writing in C++. 我是用C ++写的。 I want to track simple objects (eg black rectangle on the white background). 我想跟踪简单的对象(例如白色背景上的黑色矩形)。 Firstly I am using goodFeaturesToTrack and then calcOpticalFlowPyrLK to find those points on another image. 首先,我使用goodFeaturesToTrack,然后使用calcOpticalFlowPyrLK在另一个图像上找到这些点。 The problem is that calcOpticalFlowPyrLK doesn't find those points. 问题是calcOpticalFlowPyrLK找不到这些点。

I have found code that does it in C, which does not work in my case: http://dasl.mem.drexel.edu/~noahKuntz/openCVTut9.html 我找到了用C语言编写的代码,在我的例子中不起作用: http//dasl.mem.drexel.edu/~noahKuntz/openCVTut9.html

I have converted it into C++: 我已将其转换为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 ImageA: http ://oi50.tinypic.com/14kv05v.jpg

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

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

I have found out that it works only for winsize = 11. I have tried using it on a moving rectangle to check how far it is from the origin. 我发现它只适用于winsize = 11.我尝试在移动的矩形上使用它来检查它与原点的距离。 It hardly ever detects all four corners. 它几乎没有检测到所有四个角落。

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 implementation of Lucas-Kanade seems to be unable to track a rectangle on a binary image. Lucas-Kanade的OpenCV实现似乎无法跟踪二进制图像上的矩形。 Am I doing something wrong or does this function just not work? 我做错了什么或者这个功能不起作用?

The Lucas Kanade method estimates the motion of a region by using the gradients in that region. Lucas Kanade方法通过使用该区域中的梯度来估计区域的运动。 It is in a case a gradient descends methods. 在一种情况下,梯度下降方法。 So if you don't have gradients in x AND y direction the method will fail. 因此,如果在x和y方向上没有渐变,则方法将失败。 The second important note is that the Lucas Kanade equation 第二个重要的注意事项是Lucas Kanade方程式

E = sum_{winsize} (Ix * u + Iy * v * It)² E = sum_ {winsize}(Ix * u + Iy * v * It)²

is an first order taylor approximation of the intensity constancy constrain. 是强度恒定约束的一阶泰勒近似。

I(x,y,t) = I(x+u,y+v,t+1) I(x,y,t)= I(x + u,y + v,t + 1)

so an restriction of the method without level (image pyramids) is that the image needs to be a linear function. 所以没有水平(图像金字塔)的方法的限制是图像需要是线性函数。 In practise this mean only small motions could be estimated, dependend from the winsize you choose. 在实践中,这意味着只能估计小动作,取决于你选择的胜利。 Thats why you use the levels, which linearise the images (It). 这就是为什么你使用水平,线性化图像(It)。 So a level of 5 is a little bit to high 3 should be enough. 所以5的水平有点高到3应该足够了。 The top level image has in your case a size of 640x480 / 2^5 = 20 x 15. 在您的情况下,顶级图像的大小为640x480 / 2 ^ 5 = 20 x 15。

Finally the problem in your code is the line: 最后你的代码中的问题是:

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

the error you get back from the lucas kanade method is the resulting SSD that means: 你从lucas kanade方法得到的错误是产生的SSD意味着:

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

It is very unlikely that the error is 0. So finally you skip all features. 错误不太可能是0.所以最后你跳过所有功能。 I have good experiences by ignoring the error, that is just a confidence measure. 我通过忽略错误获得了很好的经验,这只是一种信心度量。 There are very good alternative confidence measures as the Foreward/Backward confidence. 作为前瞻/后退信心,有非常好的替代信心措施。 You could also start experiments by ignoring the status flag if too much feaurtes are discard 如果丢弃太多的女性,你也可以通过忽略状态标志来开始实验

KLT does point tracking by finding a transformation between two sets of points regarding a certain window. KLT通过找到关于某个窗口的两组点之间的转换来进行点跟踪。 The window size is an area over which each point will be chased in order to match it on the other frame. 窗口大小是一个区域,在该区域上将追逐每个点以便在另一个帧上匹配它。

It is another algorithm based on gradient that find the good features to track. 它是另一种基于梯度的算法,可以找到跟踪的好特征。

Normally KLT uses a pyramidal approach in order to maintain tracking even with big movements. 通常KLT使用金字塔方法以便即使在大运动时也能保持跟踪。 It probably uses at "maxLevel" times for the "window sized" you specified. 它可能在“maxLevel”时间用于您指定的“窗口大小”。

Never tried KLT on binary images. 从未在二进制图像上试过KLT。 The problem might be on KLT implementation that begin the search in a wrong direction and then just lost the points. 问题可能出在KLT实施上,开始向错误的方向搜索,然后就失去了积分。 When you change the windows size then the search algorithm changes also. 当您更改窗口大小时,搜索算法也会更改。 On you're picture you have only 4 interest point maximum and only on 1 pixel. 在你的照片上,你只有4个兴趣点,只有1个像素。

These are parameters you're interested in : 这些是您感兴趣的参数:

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

Suggestion : 建议:

  • Did you try with natural pictures ? 你尝试过自然图片吗? (two photos for instance), you'll have much more features to track. (例如两张照片),您将拥有更多要跟踪的功能。 4 or less is quite hard to keep. 4或更少是很难保持。 I would try this first 我先试试这个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM