我正在使用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;
}
答案 0 :(得分:1)
关于我的评论,这里有一个使用OpenCV拼接类的小代码片段:
#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);
}
正如您所看到的,这是一个非常高级的编程,几乎涵盖了上述所有步骤。
答案 1 :(得分:0)
在找到单应性后,请在代码中进行以下更改
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拼接类来获得更强大的结果。