OpenCV 2.4.2 calcOpticalFlowPyrLK 找不到任何点

OpenCV 2.4.2 calcOpticalFlowPyrLK doesn't find any points

本文关键字:任何点 找不到 OpenCV calcOpticalFlowPyrLK      更新时间:2023-10-16

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

图片A:http://oi50.tinypic.com/14kv05v.jpg

图片B:http://oi46.tinypic.com/4l3xom.jpg

图片C: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实现似乎无法跟踪二进制图像上的矩形。是我做错了什么,还是这个功能不起作用?

Lucas Kanade方法通过使用区域中的梯度来估计该区域的运动。这是一种梯度下降的方法。因此,如果在x和y方向上没有梯度,该方法将失败。第二个重要的注意事项是Lucas Kanade方程

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

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

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

因此没有级别(图像金字塔)的方法的限制是图像需要是线性函数。在实践中,这意味着只能根据你选择的winsize来估计小动作。这就是为什么你使用的水平,线性化的图像(它)。因此,5的水平有点高,3就足够了。在您的情况下,顶级图像的大小为640x480/2^5=20x15。

最后,代码中的问题是:

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

从lucas kanade方法返回的错误是生成的SSD,意思是:

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

错误不太可能为0。所以最后您可以跳过所有功能。我有忽略错误的好经验,这只是一个信心的衡量标准。有非常好的替代信心指标,如前向/后向信心。如果有太多的feaurtes被丢弃,您也可以忽略状态标志来开始实验

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或以下是很难保持的。我会先试试这个