LATCH_match.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #include <iostream>
  2. #include "opencv2/opencv_modules.hpp"
  3. #ifdef HAVE_OPENCV_XFEATURES2D
  4. #include <opencv2/core.hpp>
  5. #include <opencv2/imgproc.hpp>
  6. #include <opencv2/highgui.hpp>
  7. #include <opencv2/features2d.hpp>
  8. #include <opencv2/xfeatures2d.hpp>
  9. #include <opencv2/imgcodecs.hpp>
  10. #include <vector>
  11. // If you find this code useful, please add a reference to the following paper in your work:
  12. // Gil Levi and Tal Hassner, "LATCH: Learned Arrangements of Three Patch Codes", arXiv preprint arXiv:1501.03719, 15 Jan. 2015
  13. using namespace std;
  14. using namespace cv;
  15. const float inlier_threshold = 2.5f; // Distance threshold to identify inliers
  16. const float nn_match_ratio = 0.8f; // Nearest neighbor matching ratio
  17. int main(int argc, char* argv[])
  18. {
  19. CommandLineParser parser(argc, argv,
  20. "{@img1 | graf1.png | input image 1}"
  21. "{@img2 | graf3.png | input image 2}"
  22. "{@homography | H1to3p.xml | homography matrix}");
  23. Mat img1 = imread( samples::findFile( parser.get<String>("@img1") ), IMREAD_GRAYSCALE);
  24. Mat img2 = imread( samples::findFile( parser.get<String>("@img2") ), IMREAD_GRAYSCALE);
  25. Mat homography;
  26. FileStorage fs( samples::findFile( parser.get<String>("@homography") ), FileStorage::READ);
  27. fs.getFirstTopLevelNode() >> homography;
  28. vector<KeyPoint> kpts1, kpts2;
  29. Mat desc1, desc2;
  30. Ptr<cv::ORB> orb_detector = cv::ORB::create(10000);
  31. Ptr<xfeatures2d::LATCH> latch = xfeatures2d::LATCH::create();
  32. orb_detector->detect(img1, kpts1);
  33. latch->compute(img1, kpts1, desc1);
  34. orb_detector->detect(img2, kpts2);
  35. latch->compute(img2, kpts2, desc2);
  36. BFMatcher matcher(NORM_HAMMING);
  37. vector< vector<DMatch> > nn_matches;
  38. matcher.knnMatch(desc1, desc2, nn_matches, 2);
  39. vector<KeyPoint> matched1, matched2, inliers1, inliers2;
  40. vector<DMatch> good_matches;
  41. for (size_t i = 0; i < nn_matches.size(); i++) {
  42. DMatch first = nn_matches[i][0];
  43. float dist1 = nn_matches[i][0].distance;
  44. float dist2 = nn_matches[i][1].distance;
  45. if (dist1 < nn_match_ratio * dist2) {
  46. matched1.push_back(kpts1[first.queryIdx]);
  47. matched2.push_back(kpts2[first.trainIdx]);
  48. }
  49. }
  50. for (unsigned i = 0; i < matched1.size(); i++) {
  51. Mat col = Mat::ones(3, 1, CV_64F);
  52. col.at<double>(0) = matched1[i].pt.x;
  53. col.at<double>(1) = matched1[i].pt.y;
  54. col = homography * col;
  55. col /= col.at<double>(2);
  56. double dist = sqrt(pow(col.at<double>(0) - matched2[i].pt.x, 2) +
  57. pow(col.at<double>(1) - matched2[i].pt.y, 2));
  58. if (dist < inlier_threshold) {
  59. int new_i = static_cast<int>(inliers1.size());
  60. inliers1.push_back(matched1[i]);
  61. inliers2.push_back(matched2[i]);
  62. good_matches.push_back(DMatch(new_i, new_i, 0));
  63. }
  64. }
  65. Mat res;
  66. drawMatches(img1, inliers1, img2, inliers2, good_matches, res);
  67. imwrite("latch_result.png", res);
  68. double inlier_ratio = inliers1.size() * 1.0 / matched1.size();
  69. cout << "LATCH Matching Results" << endl;
  70. cout << "*******************************" << endl;
  71. cout << "# Keypoints 1: \t" << kpts1.size() << endl;
  72. cout << "# Keypoints 2: \t" << kpts2.size() << endl;
  73. cout << "# Matches: \t" << matched1.size() << endl;
  74. cout << "# Inliers: \t" << inliers1.size() << endl;
  75. cout << "# Inliers Ratio: \t" << inlier_ratio << endl;
  76. cout << endl;
  77. imshow("result", res);
  78. waitKey();
  79. return 0;
  80. }
  81. #else
  82. int main()
  83. {
  84. std::cerr << "OpenCV was built without xfeatures2d module" << std::endl;
  85. return 0;
  86. }
  87. #endif