【问题标题】:Issues with sticthing together two images将两张图片拼接在一起的问题
【发布时间】:2014-10-15 22:42:47
【问题描述】:

我正在使用 C++ 在 Opencv 中编程,并且在重叠点处扭曲两个图像时遇到了一些困难。我使用的是标准类型方法:检测关键点,提取描述符,匹配描述符,找到单应性,使用单应性将图像 2 映射到图像 1 的参考,然后将两个图像拼接在一起。

代码在最终图像下方是http://madda99.imgur.com/all/。任何关于如何对齐两个图像的建议/帮助将不胜感激。

#include <iostream>
#include <stdio.h>      /* printf */
#include <time.h>
#include <Windows.h>

#include "opencv2/nonfree/features2d.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/imgproc/imgproc.hpp"
//#include <cv.h>

using namespace cv;
using namespace std;


/** @function main */
int main( int argc, char** argv )
{
// if( argc != 3 )
 //{ readInImages(); return -1; }



    Mat image1 = imread(argc == 2 ? argv[1] : "sat1.png", 1);
      if (image1.empty())
      {
        cout << "Cannot open image!" << endl;
        return -1;
      }
      imshow("image", image1);
      waitKey(0);
     // return 0;

      Mat image2 = imread(argc == 2 ? argv[2] : "sat2.png", 1);
           if (image2.empty())
         {
         cout << "Cannot open image!" << endl;
         return -1;
         }
         imshow("image", image2);
         waitKey(0);



Mat img_gray1 = image1.clone();
Mat img_gray2 = image2.clone();

//Mat gray_image2;

cvtColor(image1, img_gray1, CV_RGB2GRAY);
cvtColor(image2, img_gray2, CV_RGB2GRAY);

imshow("image",img_gray1);
waitKey(0);
imshow("image",img_gray2);
waitKey(0);


if( !img_gray1.data || !img_gray2.data )
 { std::cout<< " --(!) Error reading images " << std::endl; return -1; }



//-- Step 1: Detect the keypoints using SURF Detector
 int minHessian = 2000;

SurfFeatureDetector detector( minHessian );

std::vector< KeyPoint > keypoints1, keypoints2;
vector<int> values;

detector.detect( img_gray1, keypoints1 );
detector.detect( img_gray2, keypoints2 );



//-- Step 2: Calculate descriptors (feature vectors)

SurfDescriptorExtractor extractor;

Mat descriptors_keypoints1, descriptors_keypoints2;

extractor.compute( img_gray1, keypoints1, descriptors_keypoints1 );
extractor.compute( img_gray2, keypoints2, descriptors_keypoints2 );


//-- Step 3: Matching descriptor vectors using FLANN matcher
if ( descriptors_keypoints1.empty() ) {
    cout << "Empty!!!!" << endl;}

//cvError(0,"MatchFinder","1st descriptor empty",__FILE__,__LINE__);

    //cvError(0,"MatchFinder","1st descriptor empty",__FILE__,__LINE__);
if ( descriptors_keypoints2.empty() ) {
    cout << "Empty!!!!" << endl;
}
  // cvError(0,"MatchFinder","2nd descriptor empty",__FILE__,__LINE__);

FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_keypoints1, descriptors_keypoints2, matches);


float dif = difftime (end,start);
printf ("Elapsed time is %f seconds.", dif );



//-- Draw Matches
Mat target;
   drawMatches(image1,keypoints1,image2,keypoints2,matches,target);
   imshow("Matches", target);
   waitKey(0);


   double max_dist = 0; double min_dist = 100;

 //-- Quick calculation of max and min distances between keypoints
    for( int i = 0; i < descriptors_keypoints1.rows; i++ )
    { double dist = matches[i].distance;
    if( dist < min_dist ) min_dist = dist;
    if( dist > max_dist ) max_dist = dist;
    }

   printf("-- Max dist : %f \n", max_dist );
    printf("-- Min dist : %f \n", min_dist );

   //-- Use only "good" matches (i.e. whose distance is less than 3*min_dist )
    std::vector< DMatch > good_matches;

   for( int i = 0; i < descriptors_keypoints1.rows; i++ )
    { if( matches[i].distance <= 3*min_dist )
    { good_matches.push_back( matches[i]); }
    }
    std::vector< Point2f > obj;
    std::vector< Point2f > scene;

   cout << descriptors_keypoints1<< endl << " "  << descriptors_keypoints1 << endl << endl;

    cout.setf( std::ios::fixed, std::ios::floatfield );
    cout.precision(1);
    cout << descriptors_keypoints1 << endl;

   for( int i = 0; i < good_matches.size(); i++ )
    {
    //-- Get the keypoints from the good matches
    obj.push_back( keypoints1[ good_matches[i].queryIdx ].pt );
    scene.push_back( keypoints2[ good_matches[i].trainIdx ].pt );
    }


   cout << obj.size() << endl;
   cout << scene.size() << endl;


   // Find the Homography Matrix
    //Mat H = findHomography(scene,obj, CV_RANSAC);
   cv:: Mat H = cv::findHomography(scene,obj, CV_RANSAC);
   // Use the Homography Matrix to warp the images
    cv::Mat result;


        Mat warpImage2;
        warpPerspective(image2, warpImage2, H, Size(image2.cols, image2.rows), INTER_CUBIC);



    cv::Mat result1;
     warpPerspective(image2,result1,H,cv::Size(image1.cols+image2.cols,image1.rows));
     cv::Mat half1(result1,cv::Rect(0,0,image2.cols,image2.rows));
     image2.copyTo(half1);
     imshow( "Two image Mosaic", result1 );


    waitKey(0);
    return 0;
    }

【问题讨论】:

  • 生成图像的 URL 是否正确?我看不见。您也可以在此处分享图片。
  • 为什么不用OpenCV的拼接模块?
  • 图片未公开
  • 抱歉我没有分享图片。试试链接i.imgur.com/FjTjfNR.jpg
  • 谢谢丹尼斯 我会看看拼接模块并实现它。我也尝试了下面的代码,它完美地完成了这项工作。 Rect 函数是否在位置 0,0 处为透视变换后的 image2 创建一个矩形?感谢您的帮助!

标签: c++ image opencv


【解决方案1】:

关于我的评论,这里是使用OpenCV的拼接类的小代码sn-p:

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/stitching/stitcher.hpp"

int main( int argc, char** argv )
{
    std::vector<cv::Mat> images;
    cv::Mat stitchedImage;
    cv::Stitcher stitcher = Stitcher::createDefault(true);

    //... Get your images (image1, image2) using command line parameters        


    //Stitch all images together, additionally you can add status/error handling
    images.push_back(image1);
    images.push_back(image2);
    stitcher.stitch(images, stitchedImage);

    cv::imshow("Stitched images", stitchedImage);
    cv::waitKey(0);
}

如您所见,这是非常高级的编程,几乎涵盖了上述所有步骤。

【讨论】:

    【解决方案2】:

    找到单应性后请在你的代码中做如下修改

     cv::Mat result;
    
    //you should use either the first line of wrap perspective or the second line not both
    
    //either this
         Mat warpImage2;
        warpPerspective(image2, warpImage2, H, Size(2*image2.cols, image2.rows));
    
     //Or This 
    
    cv::Mat result1;
     warpPerspective(image2,result1,H,cv::Size(image2.cols+image1.cols,image2.rows));
     // Since you are providing image2 as input image for wrap perspective you have to do the changes as below to copy the image 
    
     // Finally copy image  on the first of full image.
    cv::Mat half1(result1,cv::Rect(0,0,image1.cols,image1.rows));
     image1.copyTo(half1);
     imshow( "Two image Mosaic", result1 );
    

    正如 Dennis 所指出的,您可以使用 opencv 拼接类来获得更稳健的结果。

    【讨论】:

    • 是否容易修改代码以包括从图像 1 到图像 2 的垂直和水平移动?目前最终结果只显示水平移位。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    • 2022-12-11
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    相关资源
    最近更新 更多