Home | History | Annotate | Download | only in feature_homography
      1 Features2D + Homography to find a known object {#tutorial_feature_homography}
      2 ==============================================
      3 
      4 Goal
      5 ----
      6 
      7 In this tutorial you will learn how to:
      8 
      9 -   Use the function @ref cv::findHomography to find the transform between matched keypoints.
     10 -   Use the function @ref cv::perspectiveTransform to map the points.
     11 
     12 Theory
     13 ------
     14 
     15 Code
     16 ----
     17 
     18 This tutorial code's is shown lines below.
     19 @code{.cpp}
     20 #include <stdio.h>
     21 #include <iostream>
     22 #include "opencv2/core.hpp"
     23 #include "opencv2/imgproc.hpp"
     24 #include "opencv2/features2d.hpp"
     25 #include "opencv2/highgui.hpp"
     26 #include "opencv2/calib3d.hpp"
     27 #include "opencv2/xfeatures2d.hpp"
     28 
     29 using namespace cv;
     30 using namespace cv::xfeatures2d;
     31 
     32 void readme();
     33 
     34 /* @function main */
     35 int main( int argc, char** argv )
     36 {
     37   if( argc != 3 )
     38   { readme(); return -1; }
     39 
     40   Mat img_object = imread( argv[1], IMREAD_GRAYSCALE );
     41   Mat img_scene = imread( argv[2], IMREAD_GRAYSCALE );
     42 
     43   if( !img_object.data || !img_scene.data )
     44   { std::cout<< " --(!) Error reading images " << std::endl; return -1; }
     45 
     46   //-- Step 1: Detect the keypoints and extract descriptors using SURF
     47   int minHessian = 400;
     48 
     49   Ptr<SURF> detector = SURF::create( minHessian );
     50 
     51   std::vector<KeyPoint> keypoints_object, keypoints_scene;
     52   Mat descriptors_object, descriptors_scene;
     53 
     54   detector->detectAndCompute( img_object, Mat(), keypoints_object, descriptors_object );
     55   detector->detectAndCompute( img_scene, Mat(), keypoints_scene, descriptors_scene );
     56 
     57   //-- Step 2: Matching descriptor vectors using FLANN matcher
     58   FlannBasedMatcher matcher;
     59   std::vector< DMatch > matches;
     60   matcher.match( descriptors_object, descriptors_scene, matches );
     61 
     62   double max_dist = 0; double min_dist = 100;
     63 
     64   //-- Quick calculation of max and min distances between keypoints
     65   for( int i = 0; i < descriptors_object.rows; i++ )
     66   { double dist = matches[i].distance;
     67     if( dist < min_dist ) min_dist = dist;
     68     if( dist > max_dist ) max_dist = dist;
     69   }
     70 
     71   printf("-- Max dist : %f \n", max_dist );
     72   printf("-- Min dist : %f \n", min_dist );
     73 
     74   //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
     75   std::vector< DMatch > good_matches;
     76 
     77   for( int i = 0; i < descriptors_object.rows; i++ )
     78   { if( matches[i].distance < 3*min_dist )
     79      { good_matches.push_back( matches[i]); }
     80   }
     81 
     82   Mat img_matches;
     83   drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
     84                good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
     85                std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
     86 
     87   //-- Localize the object
     88   std::vector<Point2f> obj;
     89   std::vector<Point2f> scene;
     90 
     91   for( size_t i = 0; i < good_matches.size(); i++ )
     92   {
     93     //-- Get the keypoints from the good matches
     94     obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
     95     scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
     96   }
     97 
     98   Mat H = findHomography( obj, scene, RANSAC );
     99 
    100   //-- Get the corners from the image_1 ( the object to be "detected" )
    101   std::vector<Point2f> obj_corners(4);
    102   obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 );
    103   obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); obj_corners[3] = cvPoint( 0, img_object.rows );
    104   std::vector<Point2f> scene_corners(4);
    105 
    106   perspectiveTransform( obj_corners, scene_corners, H);
    107 
    108   //-- Draw lines between the corners (the mapped object in the scene - image_2 )
    109   line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), scene_corners[1] + Point2f( img_object.cols, 0), Scalar(0, 255, 0), 4 );
    110   line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), scene_corners[2] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
    111   line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), scene_corners[3] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
    112   line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), scene_corners[0] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
    113 
    114   //-- Show detected matches
    115   imshow( "Good Matches & Object detection", img_matches );
    116 
    117   waitKey(0);
    118   return 0;
    119   }
    120 
    121   /* @function readme */
    122   void readme()
    123   { std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }
    124 @endcode
    125 Explanation
    126 -----------
    127 
    128 Result
    129 ------
    130 
    131 -#  And here is the result for the detected object (highlighted in green)
    132 
    133     ![](images/Feature_Homography_Result.jpg)
    134