OpenCV warpPerspective 的问题

Posted

技术标签:

【中文标题】OpenCV warpPerspective 的问题【英文标题】:Problems with OpenCV warpPerspective 【发布时间】:2014-03-26 10:21:50 【问题描述】:

我正在开发一个带有移动摄像头的 android 背景减法项目。我正在尝试使用特征匹配、findHomography 和 warpPerspective 来查找两帧之间的重叠像素。但是,我得到的输出有点不正确。我对图像处理很陌生,所以我不熟悉所有术语。我有两个主要问题:

1) warpPerspective 的结果过度扭曲 - 例如图像倾斜,图像中的对象被翻转、挤压等。我该如何解决这个问题?

2) 我有时会收到“OpenCV 错误:断言失败”错误,这会导致我的应用程序崩溃。此错误映射到 warpPerspective。注意:image1(前一帧)和image2(当前帧)的尺寸相同。在检测特征(当前来自 RGB)之前,我将图像转换为灰色。我有时会在使用 findHomography 时遇到类似的“OpenCV 断言失败”错误,但我了解到它至少需要 4 分 - 因此添加 if 语句解决了它,但不确定如何使用 warpPerspective 解决错误。

我得到的错误:

02-24 15:30:49.554: E/cv::error()(4589): OpenCV Error: Assertion failed (type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U)) 
    in void cv::batchDistance(cv::InputArray, cv::InputArray, cv::OutputArray, int, cv::OutputArray, int, int, cv::InputArray, int, bool), 
    file /home/reports/ci/slave_desktop/50-SDK/opencv/modules/core/src/stat.cpp, line 2473

我的代码:

void stitchFrames()

    //convert frames to grayscale
    image1 = prevFrame.clone();
    image2 = currFrame.clone();

    if(colourSpace==1) //convert from RGB to gray
        cv::cvtColor(image1, image1Gray,CV_RGB2GRAY);
        cv::cvtColor(image2, image2Gray,CV_RGB2GRAY);
    
    else if(colourSpace==2) //convert from HSV to gray
        cv::cvtColor(image1, image1Gray,CV_HSV2RGB);
        cv::cvtColor(image1Gray,image1Gray,CV_RGB2GRAY);
        cv::cvtColor(image2, image1Gray,CV_HSV2RGB);
        cv::cvtColor(image2Gray,image1Gray,CV_RGB2GRAY);
    

    else if(colourSpace==3) //no need for conversion
        image1Gray = image1;
        image2Gray = image2;
    

    //----FEATURE DETECTION----

    //key points
    std::vector<KeyPoint> keypoints1, keypoints2;

    int minHessian;

    cv::FastFeatureDetector detector;

    detector.detect(image1Gray,keypoints1); //prevFrame
    detector.detect(image2Gray,keypoints2); //currFrame

    KeyPoint kp = keypoints2[4];
    Point2f p = kp.pt;
    float i = p.y;

    //---FEATURE EXTRACTION----

    //extracted descriptors
    cv::Mat descriptors1,descriptors2;

    OrbDescriptorExtractor extractor;
    extractor.compute(image1,keypoints1,descriptors1); //prevFrame
    extractor.compute(image2,keypoints2,descriptors2); //currFrame

    //----FEATURE MATCHING----

    //BruteForceMacher

    BFMatcher matcher;

    std::vector< cv::DMatch > matches; //result of matching descriptors
    std::vector< cv::DMatch > goodMatches; //result of sifting matches to get only 'good' matches

    matcher.match(descriptors1,descriptors2,matches);

    //----HOMOGRAPY - WARP-PERSPECTIVE - PERSPECTIVE-TRANSFORM----

    double maxDist = 0.0; //keep track of max distance from the matches
    double minDist = 80.0; //keep track of min distance from the matches

    //calculate max & min distances between keypoints
    for(int i=0; i<descriptors1.rows;i++)
        DMatch match = matches[i];

        float dist = match.distance;
        if (dist<minDist) minDist = dist;
        if(dist>maxDist) maxDist=dist;
    

    //get only the good matches
    for( int i = 0; i < descriptors1.rows; i++ )
        DMatch match = matches[i];
        if(match.distance< 500)
            goodMatches.push_back(match);
        
    

    std::vector< Point2f > obj;
    std::vector< Point2f > scene;

    //get the keypoints from the good matches
    for( int i = 0; i < goodMatches.size(); i++ )

        //--keypoints from image1
        DMatch match1 = goodMatches[i];
        int qI1 = match1.trainIdx;
        KeyPoint kp1 = keypoints2[qI1];
        Point2f point1 = kp1.pt;
        obj.push_back(point1);

        //--keypoints from image2
        DMatch match2 = goodMatches[i];
        int qI2 = match2.queryIdx;
        KeyPoint kp2 = keypoints1[qI2];
        Point2f point2 = kp2.pt;
        scene.push_back(point2);

    

    //calculate the homography matrix
    if(goodMatches.size() >=4)
        Mat H = findHomography(obj,scene, CV_RANSAC);

        warpPerspective(image2,warpResult,H,Size(image1.cols,image1.rows));
    

【问题讨论】:

您找到解决方案了吗?我也有类似的问题。 【参考方案1】:

关于您的第一个问题,我认为您提到的失真是由于以下事实:

1234563

然后您在函数warpPerspective 中使用H,就好像它将图像2 中的坐标映射到图像1 中的坐标一样,因为您希望它将image2 转换为warpResult,我猜这是应该缝合到image1

因此,您应该估计单应性H 如下:Mat H = findHomography(scene, obj, CV_RANSAC);

关于你的第二个问题,我认为它是由这条指令提出的:

matcher.match(descriptors1,descriptors2,matches);

错误表示表达式

(type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U))

被发现是假的,而函数工作应该是真的。解决了类似问题here:在调用match函数之前,需要手动检查以下是否为真:

(descriptors1.type()==descriptors2.type() && descriptors1.cols==descriptors2.cols)

【讨论】:

感谢您的回复。您对第二个问题的建议有效 - 我不再看到错误发生。但是,在遵循您的建议Mat H = findHomography(scene, obj, CV_RANSAC); 之后,第一个问题中的问题仍然存在【参考方案2】:

关于(1),我的猜测是您估计的单应性是基于不良匹配。

首先我将使用 ORB 检测器而不是 FAST,然后更改 findHomography ransacReprojThreshold 参数。默认值为3,详情:

ransacReprojThreshold:

将点对视为内点的最大允许重投影误差 (仅用于 RANSAC 方法)。也就是说,如果:

| dstPoints_i - convertPointsHomogeneous(H * srcPoints_i) | > ransacReprojThreshold

那么点 i 被认为是异常值。如果 srcPoints 和 dstPoints 以像素为单位,通常设置此参数是有意义的 介于 1 到 10 之间。

换句话说,假设默认为 3 个像素,如果在将单应性应用于 srcPoint 后,它到 dstPoint 的距离大于 3 个像素,则该对被认为是内点(即:好)。

这只是一个开始,它还将帮助您找到更好的过滤器来获得良好的匹配和良好的单应性,您会找到一些关于这些的答案:

OpenCV Orb not finding matches..

How can you tell if a homography matrix is acceptable or not?

【讨论】:

感谢您的回复。我已经尝试过您的建议,但不幸的是它并没有太大变化。实际上,我首先尝试了 2 张图像,但变形并不完美 - 不出所料,在实时视频源上,输出并不像预期的那样。我尝试了几种算法组合,但我认为它并没有太大的区别(除了速度之外)。我也因无法访问 OpenCV Android 上的 SURF/SIFT 而受到限制。我会研究你链接的主题。 但是经线总是错的吗?至少一些视频帧应该没问题。 在某些视频帧上,没问题。但大多数时候,它是歪斜的,图像通常是扭曲的。我正在尝试使用 warpPerspective 的输出来检测使用背景减法的新奇事物 - 所以当我开始稍微移动相机时,输出的新奇事物通常会失真。 这和我给你的答案是一致的。

以上是关于OpenCV warpPerspective 的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 OpenGL 模拟 OpenCV 的 warpPerspective 功能(透视变换)

与 OpenCV findHomography 和 warpPerspective 混淆

初学opencv c++学习笔记透视变换--warpPerspective()

在 openCV warpPerspective 中,如何转换左侧图像并将其拼接到右侧图像?

在perspectiveWarp/warpPerspective 之后Android-Android OpenCV 得到空白(黑色)图像?

利用OpenCV的函数warpPerspective()作图像的透视变换