Main steps of the code:
- Load two images;
- Convert to gray scale;
- Using SURF detector to find SURF descriptor in both images;
- matching the SURF descriptor using FLANN Matcher;
- Postprocessing matches to find good matches
- Using RANSAC to estimate the Homography matrix using the matched SURF descriptors;
- Warping the images based on the homography matrix
The image shows the definition of Homography which transforms 2d Planar point to the image plane.
Stiching image result.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <iostream> | |
#include "opencv2/opencv.hpp" | |
#include "opencv2/nonfree/nonfree.hpp" | |
using namespace cv; | |
using namespace std; | |
int main() | |
{ | |
// Load the image | |
Mat image1 = imread("image1.jpg",1 ); | |
Mat image2 = imread("image2.jpg",1); | |
Mat img1_gray; | |
Mat img2_gray; | |
//convert to Grayscale | |
cvtColor(image1,img1_gray,CV_RGB2GRAY ); | |
cvtColor(image2,img2_gray,CV_RGB2GRAY ); | |
imshow("Image1", image1); | |
imshow("Image2", image2); | |
if(!img1_gray.data || !img2_gray.data ) | |
{ | |
cout << " -- (!) Error reading Images " << endl; | |
return -1; | |
} | |
// -- Step 1: Detect the keypoints using SURF Detector | |
int minHessian = 400; | |
SurfFeatureDetector detector( minHessian ); | |
vector< KeyPoint> keypoints_object, keypoints_scene; | |
detector.detect(img1_gray, keypoints_object ); | |
detector.detect(img2_gray, keypoints_scene ); | |
// -- Step 2: Calculate descriptors (feature vectors) | |
SurfDescriptorExtractor extractor; | |
Mat descriptors_object, descriptors_scene; | |
extractor.compute(img1_gray,keypoints_object, descriptors_object ) ; | |
extractor.compute(img2_gray,keypoints_scene , descriptors_scene ) ; | |
// -- Step 3: Matching descriptor vector using FLANN matcher | |
FlannBasedMatcher matcher; | |
vector<DMatch> matches; | |
matcher.match(descriptors_object, descriptors_scene, matches ); | |
double max_dist = 0; double min_dist = 100; | |
// -- Quick calculation of Max and Min distances between keypoints | |
for (int i = 0; i < descriptors_object.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, those with distance smaller than 3*mindist) | |
vector<DMatch> good_matches; | |
for (int i = 0; i < descriptors_object.rows; i++) | |
{ | |
if ( matches[i].distance < 3*min_dist ) | |
{ | |
good_matches.push_back( matches[i] ); | |
} | |
} | |
// Draw Good Matches | |
Mat img_goodmatches; | |
drawMatches(image1, keypoints_object, image2, keypoints_scene,good_matches,img_goodmatches,Scalar::all(-1),Scalar::all(-1),vector<char>(),DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); | |
imshow("GoodMatches", img_goodmatches ); | |
imwrite("MatchingResult.jpg", img_goodmatches); | |
vector< Point2f > obj; | |
vector< Point2f > scene; | |
for (int i = 0; i < good_matches.size(); i++) | |
{ | |
// -- Get the keypoints from the good matches | |
obj.push_back( keypoints_object[ good_matches[i].queryIdx].pt); | |
scene.push_back(keypoints_scene[ good_matches[i].trainIdx].pt); | |
} | |
// -- Find the Homography Matrix | |
Mat H = findHomography( obj, scene, CV_RANSAC ) ; | |
cout << "Homography Matrix" << H << endl; | |
// -- Use the Homography Matrix to warp the images, convert image 1 to image 2 using H | |
Mat result; | |
warpPerspective(image1, result, H, cv::Size(image1.cols + image2.cols,image1.rows)); | |
Mat half(result, cv::Rect(0,0,image2.cols,image2.rows)); // IMPT: Mat 'half' refer to the same address as the left part of 'result' | |
image2.copyTo(half); | |
imshow("Stiching Result", result ); | |
imshow("Stiching Result2", half ); | |
imwrite("StichingResult.jpg", result); | |
waitKey(0); | |
return 0; | |
} |