/** * @file SURF_Homography * @brief SURF detector + descriptor + FLANN Matcher + FindHomography * @author A. Huaman */ #include #include #include "opencv2/core/core.hpp" #include "opencv2/features2d/features2d.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/calib3d/calib3d.hpp" using namespace cv; void readme(); /** * @function main * @brief Main function */ int main( int argc, char** argv ) { if( argc != 3 ) { readme(); return -1; } Mat img_1 = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE ); Mat img_2 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE ); if( !img_1.data || !img_2.data ) { std::cout<< " --(!) Error reading images " << std::endl; return -1; } //-- Step 1: Detect the keypoints using SURF Detector int minHessian = 400; SurfFeatureDetector detector( minHessian ); std::vector keypoints_1, keypoints_2; detector.detect( img_1, keypoints_1 ); detector.detect( img_2, keypoints_2 ); //-- Step 2: Calculate descriptors (feature vectors) SurfDescriptorExtractor extractor; Mat descriptors_1, descriptors_2; extractor.compute( img_1, keypoints_1, descriptors_1 ); extractor.compute( img_2, keypoints_2, descriptors_2 ); //-- Step 3: Matching descriptor vectors using FLANN matcher FlannBasedMatcher matcher; std::vector< DMatch > matches; matcher.match( descriptors_1, descriptors_2, matches ); double max_dist = 0; double min_dist = 100; //-- Quick calculation of max and min distances between keypoints for( int i = 0; i < descriptors_1.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 ); //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist ) std::vector< DMatch > good_matches; for( int i = 0; i < descriptors_1.rows; i++ ) { if( matches[i].distance < 3*min_dist ) { good_matches.push_back( matches[i]); } } Mat img_matches; drawMatches( img_1, keypoints_1, img_2, keypoints_2, good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); //-- Localize the object from img_1 in img_2 std::vector obj; std::vector scene; for( int i = 0; i < good_matches.size(); i++ ) { //-- Get the keypoints from the good matches obj.push_back( keypoints_1[ good_matches[i].queryIdx ].pt ); scene.push_back( keypoints_2[ good_matches[i].trainIdx ].pt ); } Mat H = findHomography( obj, scene, CV_RANSAC ); //-- Get the corners from the image_1 ( the object to be "detected" ) Point2f obj_corners[4] = { cvPoint(0,0), cvPoint( img_1.cols, 0 ), cvPoint( img_1.cols, img_1.rows ), cvPoint( 0, img_1.rows ) }; Point scene_corners[4]; //-- Map these corners in the scene ( image_2) for( int i = 0; i < 4; i++ ) { double x = obj_corners[i].x; double y = obj_corners[i].y; double Z = 1./( H.at(2,0)*x + H.at(2,1)*y + H.at(2,2) ); double X = ( H.at(0,0)*x + H.at(0,1)*y + H.at(0,2) )*Z; double Y = ( H.at(1,0)*x + H.at(1,1)*y + H.at(1,2) )*Z; scene_corners[i] = cvPoint( cvRound(X) + img_1.cols, cvRound(Y) ); } //-- Draw lines between the corners (the mapped object in the scene - image_2 ) line( img_matches, scene_corners[0], scene_corners[1], Scalar(0, 255, 0), 2 ); line( img_matches, scene_corners[1], scene_corners[2], Scalar( 0, 255, 0), 2 ); line( img_matches, scene_corners[2], scene_corners[3], Scalar( 0, 255, 0), 2 ); line( img_matches, scene_corners[3], scene_corners[0], Scalar( 0, 255, 0), 2 ); //-- Show detected matches imshow( "Good Matches & Object detection", img_matches ); waitKey(0); return 0; } /** * @function readme */ void readme() { std::cout << " Usage: ./SURF_descriptor " << std::endl; }