OpenCV 2.4.2 calcOpticalFlowPyrLK找不到任何点 [英] OpenCV 2.4.2 calcOpticalFlowPyrLK doesn't find any points

查看:472
本文介绍了OpenCV 2.4.2 calcOpticalFlowPyrLK找不到任何点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Linux上使用OpenCV 2.4.2。我用C ++编写。我想跟踪简单的对象(例如白色背景上的黑色矩形)。首先我使用goodFeaturesToTrack然后calcOpticalFlowPyrLK找到另一个图像上的那些点。问题是,calcOpticalFlowPyrLK找不到这些点。



我发现代码在C中,它不工作在我的情况下: http://dasl.mem.drexel.edu/~noahKuntz/openCVTut9.html



我已经将它转换为C ++:

  int main(int, *){
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> cornerA;

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

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

//我不知道它是做什么
// cornerSubPix(imgAgray,cornersA,Size(15,15),Size(-1,-1) ,
// TermCriteria(TermCriteria :: COUNT + TermCriteria :: EPS,20,0.03));

vector< Point2f>角B;
vector< uchar>状态;
vector< float>错误;

// winsize必须是11或13,否则什么都找不到
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] ){
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>特征;
goodFeaturesToTrack(org,features,30,0.01,30);
std :: cout<< POINTS FOUND:< std :: endl;
for(unsigned int i = 0; i< features.size(); i ++){
std :: cout< 发现点:<特征[i] .x;
std :: cout<< <特征[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>发现;
vector< uchar>状态;
vector< float>错误;
calcOpticalFlowPyrLK(org,frame,features,found,status,error,
Size(11,11),5);

席位显示;
cvtColor(frame,display,CV_GRAY2BGR);

for(unsigned int i = 0; i if(status [i] == 0 || error [i] ){
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的Lucas-Kanade似乎无法在二进制图像上跟踪矩形。

解决方案

Lucas Kanade方法通过使用以下方法来估计区域的运动:该区域的梯度。它是在一种情况下梯度下降方法。所以如果你没有在x和y方向的梯度方法将失败。第二个重要的注意事项是Lucas Kanard方程



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



p是强度常数约束的一阶泰勒近似。



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



所以对无水平(图像金字塔)的方法的限制是图像需要是线性函数。在实践中,这意味着只有小的运动可以估计,依赖于你选择的winsize。这就是为什么你使用的水平,线性化的图像(It)。所以一个级别5是有点高到3应该就够了。顶层图片的大小为640x480 / 2 ^ 5 = 20 x 15。



最后,代码中的问题是:

  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被丢弃


I am using OpenCV 2.4.2 on Linux. I am writing in C++. I want to track simple objects (e.g. black rectangle on the white background). Firstly I am using goodFeaturesToTrack and then calcOpticalFlowPyrLK to find those points on another image. The problem is that calcOpticalFlowPyrLK doesn't find those points.

I have found code that does it in C, which does not work in my case: http://dasl.mem.drexel.edu/~noahKuntz/openCVTut9.html

I have converted it into 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

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. 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. 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. 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. The second important note is that the Lucas Kanade equation

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)

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). So a level of 5 is a little bit to high 3 should be enough. The top level image has in your case a size of 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:

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. 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

这篇关于OpenCV 2.4.2 calcOpticalFlowPyrLK找不到任何点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆