1AKAZE local features matching {#tutorial_akaze_matching} 2============================= 3 4Introduction 5------------ 6 7In this tutorial we will learn how to use AKAZE @cite ANB13 local features to detect and match keypoints on 8two images. 9We will find keypoints on a pair of images with given homography matrix, match them and count the 10 11number of inliers (i. e. matches that fit in the given homography). 12 13You can find expanded version of this example here: 14<https://github.com/pablofdezalc/test_kaze_akaze_opencv> 15 16Data 17---- 18 19We are going to use images 1 and 3 from *Graffity* sequence of Oxford dataset. 20 21![](images/graf.png) 22 23Homography is given by a 3 by 3 matrix: 24@code{.none} 257.6285898e-01 -2.9922929e-01 2.2567123e+02 263.3443473e-01 1.0143901e+00 -7.6999973e+01 273.4663091e-04 -1.4364524e-05 1.0000000e+00 28@endcode 29You 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 120Found matches 121------------- 122 123![](images/res.png) 124 125A-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