OpenCV的2.4.2 calcOpticalFlowPyrLK没有找到任何点(OpenCV 2.

2019-07-30 15:45发布

我在Linux上使用OpenCV的2.4.2。 我写在C ++。 我想简单的跟踪对象(在白色背景例如,黑色矩形)。 首先我使用goodFeaturesToTrack然后calcOpticalFlowPyrLK找到另一个图像上这些点。 问题是,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;
        }
    }

}

卢卡斯金出武雄的OpenCV的执行似乎是无法跟踪的二进制图像上的矩形。 我是不是做错了什么或没有此功能只是没有工作?

Answer 1:

卢卡斯奏方法通过在该区域中使用的梯度估计的区域的运动。 它是在一个梯度下降方法的情况。 所以,如果你没有在X和Y方向梯度的方​​法将失败。 第二个重要的一点是,卢卡斯金出武雄方程

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

是强度恒定约束的一阶泰勒近似。

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

因此该方法的无电平(图像金字塔)的限制是,该图像必须是一个线性函数。 在实践中,这仅仅意味着小的运动可估计,从你选择使用winsize的依赖性。 为什么你使用水平,线性化图像(IT)多数民众赞成。 所以5级是有点高3应该是足够的。 你的情况的顶层图像具有尺寸640×480/2 ^ 5 = 20×15。

最后,在你的代码的问题是线路:

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

你从卢卡斯 - 卡纳德方法后面的错误是导致SSD,这意味着:

误差总和=(使用winsize)(I(X,Y,0) - I(X + U,Y + U,1)^ 2)/(使用winsize *使用winsize)

这是不太可能的误差为0,所以最后你跳过所有功能。 我有忽略错误的好经验,这仅仅是一个信心的措施。 有很好的替代信心措施的Foreward /快退的信心。 您也可以通过忽略状态标志,如果太多feaurtes被丢弃开始实验



Answer 2:

康莱特注射液通过寻找关于某个窗口两组点之间的转换也点跟踪。 窗口的大小是在其每一个点,以便匹配它的另一帧上被追赶的区域。

它是一种基于梯度找到很好的功能来跟踪另一种算法。

通常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以下是相当难以维持。 我先试试这个


文章来源: OpenCV 2.4.2 calcOpticalFlowPyrLK doesn't find any points