Home | History | Annotate | Download | only in akaze_matching
      1 AKAZE local features matching {#tutorial_akaze_matching}
      2 =============================
      3 
      4 Introduction
      5 ------------
      6 
      7 In this tutorial we will learn how to use AKAZE @cite ANB13 local features to detect and match keypoints on
      8 two images.
      9 We will find keypoints on a pair of images with given homography matrix, match them and count the
     10 
     11 number of inliers (i. e. matches that fit in the given homography).
     12 
     13 You can find expanded version of this example here:
     14 <https://github.com/pablofdezalc/test_kaze_akaze_opencv>
     15 
     16 Data
     17 ----
     18 
     19 We are going to use images 1 and 3 from *Graffity* sequence of Oxford dataset.
     20 
     21 ![](images/graf.png)
     22 
     23 Homography is given by a 3 by 3 matrix:
     24 @code{.none}
     25 7.6285898e-01  -2.9922929e-01   2.2567123e+02
     26 3.3443473e-01   1.0143901e+00  -7.6999973e+01
     27 3.4663091e-04  -1.4364524e-05   1.0000000e+00
     28 @endcode
     29 You can find the images (*graf1.png*, *graf3.png*) and homography (*H1to3p.xml*) in
     30 *opencv/samples/cpp*.
     31 
     32 ### Source Code
     33 
     34 @include cpp/tutorial_code/features2D/AKAZE_match.cpp
     35 
     36 ### Explanation
     37 
     38 -#  **Load images and homography**
     39     @code{.cpp}
     40     Mat img1 = imread("graf1.png", IMREAD_GRAYSCALE);
     41     Mat img2 = imread("graf3.png", IMREAD_GRAYSCALE);
     42 
     43     Mat homography;
     44     FileStorage fs("H1to3p.xml", FileStorage::READ);
     45     fs.getFirstTopLevelNode() >> homography;
     46     @endcode
     47     We are loading grayscale images here. Homography is stored in the xml created with FileStorage.
     48 
     49 -#  **Detect keypoints and compute descriptors using AKAZE**
     50     @code{.cpp}
     51     vector<KeyPoint> kpts1, kpts2;
     52     Mat desc1, desc2;
     53 
     54     AKAZE akaze;
     55     akaze(img1, noArray(), kpts1, desc1);
     56     akaze(img2, noArray(), kpts2, desc2);
     57     @endcode
     58     We create AKAZE object and use it's *operator()* functionality. Since we don't need the *mask*
     59     parameter, *noArray()* is used.
     60 
     61 -#  **Use brute-force matcher to find 2-nn matches**
     62     @code{.cpp}
     63     BFMatcher matcher(NORM_HAMMING);
     64     vector< vector<DMatch> > nn_matches;
     65     matcher.knnMatch(desc1, desc2, nn_matches, 2);
     66     @endcode
     67     We use Hamming distance, because AKAZE uses binary descriptor by default.
     68 
     69 -#  **Use 2-nn matches to find correct keypoint matches**
     70     @code{.cpp}
     71     for(size_t i = 0; i < nn_matches.size(); i++) {
     72         DMatch first = nn_matches[i][0];
     73         float dist1 = nn_matches[i][0].distance;
     74         float dist2 = nn_matches[i][1].distance;
     75 
     76         if(dist1 < nn_match_ratio * dist2) {
     77             matched1.push_back(kpts1[first.queryIdx]);
     78             matched2.push_back(kpts2[first.trainIdx]);
     79         }
     80     }
     81     @endcode
     82     If the closest match is *ratio* closer than the second closest one, then the match is correct.
     83 
     84 -#  **Check if our matches fit in the homography model**
     85     @code{.cpp}
     86     for(int i = 0; i < matched1.size(); i++) {
     87         Mat col = Mat::ones(3, 1, CV_64F);
     88         col.at<double>(0) = matched1[i].pt.x;
     89         col.at<double>(1) = matched1[i].pt.y;
     90 
     91         col = homography * col;
     92         col /= col.at<double>(2);
     93         float dist = sqrt( pow(col.at<double>(0) - matched2[i].pt.x, 2) +
     94                            pow(col.at<double>(1) - matched2[i].pt.y, 2));
     95 
     96         if(dist < inlier_threshold) {
     97             int new_i = inliers1.size();
     98             inliers1.push_back(matched1[i]);
     99             inliers2.push_back(matched2[i]);
    100             good_matches.push_back(DMatch(new_i, new_i, 0));
    101         }
    102     }
    103     @endcode
    104     If the distance from first keypoint's projection to the second keypoint is less than threshold,
    105     then it it fits in the homography.
    106 
    107     We create a new set of matches for the inliers, because it is required by the drawing function.
    108 
    109 -#  **Output results**
    110     @code{.cpp}
    111     Mat res;
    112     drawMatches(img1, inliers1, img2, inliers2, good_matches, res);
    113     imwrite("res.png", res);
    114     ...
    115     @endcode
    116     Here we save the resulting image and print some statistics.
    117 
    118 ### Results
    119 
    120 Found matches
    121 -------------
    122 
    123 ![](images/res.png)
    124 
    125 A-KAZE Matching Results
    126 -----------------------
    127 @code{.none}
    128  Keypoints 1:   2943
    129  Keypoints 2:   3511
    130  Matches:       447
    131  Inliers:       308
    132  Inlier Ratio: 0.689038}
    133 @endcode
    134