AKAZEMatchDemo.java 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import java.io.File;
  2. import java.io.IOException;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import javax.xml.parsers.DocumentBuilder;
  6. import javax.xml.parsers.DocumentBuilderFactory;
  7. import javax.xml.parsers.ParserConfigurationException;
  8. import org.opencv.core.Core;
  9. import org.opencv.core.CvType;
  10. import org.opencv.core.DMatch;
  11. import org.opencv.core.KeyPoint;
  12. import org.opencv.core.Mat;
  13. import org.opencv.core.MatOfDMatch;
  14. import org.opencv.core.MatOfKeyPoint;
  15. import org.opencv.core.Scalar;
  16. import org.opencv.features2d.AKAZE;
  17. import org.opencv.features2d.DescriptorMatcher;
  18. import org.opencv.features2d.Features2d;
  19. import org.opencv.highgui.HighGui;
  20. import org.opencv.imgcodecs.Imgcodecs;
  21. import org.w3c.dom.Document;
  22. import org.xml.sax.SAXException;
  23. class AKAZEMatch {
  24. public void run(String[] args) {
  25. //! [load]
  26. String filename1 = args.length > 2 ? args[0] : "../data/graf1.png";
  27. String filename2 = args.length > 2 ? args[1] : "../data/graf3.png";
  28. String filename3 = args.length > 2 ? args[2] : "../data/H1to3p.xml";
  29. Mat img1 = Imgcodecs.imread(filename1, Imgcodecs.IMREAD_GRAYSCALE);
  30. Mat img2 = Imgcodecs.imread(filename2, Imgcodecs.IMREAD_GRAYSCALE);
  31. if (img1.empty() || img2.empty()) {
  32. System.err.println("Cannot read images!");
  33. System.exit(0);
  34. }
  35. File file = new File(filename3);
  36. DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  37. DocumentBuilder documentBuilder;
  38. Document document;
  39. Mat homography = new Mat(3, 3, CvType.CV_64F);
  40. double[] homographyData = new double[(int) (homography.total()*homography.channels())];
  41. try {
  42. documentBuilder = documentBuilderFactory.newDocumentBuilder();
  43. document = documentBuilder.parse(file);
  44. String homographyStr = document.getElementsByTagName("data").item(0).getTextContent();
  45. String[] splited = homographyStr.split("\\s+");
  46. int idx = 0;
  47. for (String s : splited) {
  48. if (!s.isEmpty()) {
  49. homographyData[idx] = Double.parseDouble(s);
  50. idx++;
  51. }
  52. }
  53. } catch (ParserConfigurationException e) {
  54. e.printStackTrace();
  55. System.exit(0);
  56. } catch (SAXException e) {
  57. e.printStackTrace();
  58. System.exit(0);
  59. } catch (IOException e) {
  60. e.printStackTrace();
  61. System.exit(0);
  62. }
  63. homography.put(0, 0, homographyData);
  64. //! [load]
  65. //! [AKAZE]
  66. AKAZE akaze = AKAZE.create();
  67. MatOfKeyPoint kpts1 = new MatOfKeyPoint(), kpts2 = new MatOfKeyPoint();
  68. Mat desc1 = new Mat(), desc2 = new Mat();
  69. akaze.detectAndCompute(img1, new Mat(), kpts1, desc1);
  70. akaze.detectAndCompute(img2, new Mat(), kpts2, desc2);
  71. //! [AKAZE]
  72. //! [2-nn matching]
  73. DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
  74. List<MatOfDMatch> knnMatches = new ArrayList<>();
  75. matcher.knnMatch(desc1, desc2, knnMatches, 2);
  76. //! [2-nn matching]
  77. //! [ratio test filtering]
  78. float ratioThreshold = 0.8f; // Nearest neighbor matching ratio
  79. List<KeyPoint> listOfMatched1 = new ArrayList<>();
  80. List<KeyPoint> listOfMatched2 = new ArrayList<>();
  81. List<KeyPoint> listOfKeypoints1 = kpts1.toList();
  82. List<KeyPoint> listOfKeypoints2 = kpts2.toList();
  83. for (int i = 0; i < knnMatches.size(); i++) {
  84. DMatch[] matches = knnMatches.get(i).toArray();
  85. float dist1 = matches[0].distance;
  86. float dist2 = matches[1].distance;
  87. if (dist1 < ratioThreshold * dist2) {
  88. listOfMatched1.add(listOfKeypoints1.get(matches[0].queryIdx));
  89. listOfMatched2.add(listOfKeypoints2.get(matches[0].trainIdx));
  90. }
  91. }
  92. //! [ratio test filtering]
  93. //! [homography check]
  94. double inlierThreshold = 2.5; // Distance threshold to identify inliers with homography check
  95. List<KeyPoint> listOfInliers1 = new ArrayList<>();
  96. List<KeyPoint> listOfInliers2 = new ArrayList<>();
  97. List<DMatch> listOfGoodMatches = new ArrayList<>();
  98. for (int i = 0; i < listOfMatched1.size(); i++) {
  99. Mat col = new Mat(3, 1, CvType.CV_64F);
  100. double[] colData = new double[(int) (col.total() * col.channels())];
  101. colData[0] = listOfMatched1.get(i).pt.x;
  102. colData[1] = listOfMatched1.get(i).pt.y;
  103. colData[2] = 1.0;
  104. col.put(0, 0, colData);
  105. Mat colRes = new Mat();
  106. Core.gemm(homography, col, 1.0, new Mat(), 0.0, colRes);
  107. colRes.get(0, 0, colData);
  108. Core.multiply(colRes, new Scalar(1.0 / colData[2]), col);
  109. col.get(0, 0, colData);
  110. double dist = Math.sqrt(Math.pow(colData[0] - listOfMatched2.get(i).pt.x, 2) +
  111. Math.pow(colData[1] - listOfMatched2.get(i).pt.y, 2));
  112. if (dist < inlierThreshold) {
  113. listOfGoodMatches.add(new DMatch(listOfInliers1.size(), listOfInliers2.size(), 0));
  114. listOfInliers1.add(listOfMatched1.get(i));
  115. listOfInliers2.add(listOfMatched2.get(i));
  116. }
  117. }
  118. //! [homography check]
  119. //! [draw final matches]
  120. Mat res = new Mat();
  121. MatOfKeyPoint inliers1 = new MatOfKeyPoint(listOfInliers1.toArray(new KeyPoint[listOfInliers1.size()]));
  122. MatOfKeyPoint inliers2 = new MatOfKeyPoint(listOfInliers2.toArray(new KeyPoint[listOfInliers2.size()]));
  123. MatOfDMatch goodMatches = new MatOfDMatch(listOfGoodMatches.toArray(new DMatch[listOfGoodMatches.size()]));
  124. Features2d.drawMatches(img1, inliers1, img2, inliers2, goodMatches, res);
  125. Imgcodecs.imwrite("akaze_result.png", res);
  126. double inlierRatio = listOfInliers1.size() / (double) listOfMatched1.size();
  127. System.out.println("A-KAZE Matching Results");
  128. System.out.println("*******************************");
  129. System.out.println("# Keypoints 1: \t" + listOfKeypoints1.size());
  130. System.out.println("# Keypoints 2: \t" + listOfKeypoints2.size());
  131. System.out.println("# Matches: \t" + listOfMatched1.size());
  132. System.out.println("# Inliers: \t" + listOfInliers1.size());
  133. System.out.println("# Inliers Ratio: \t" + inlierRatio);
  134. HighGui.imshow("result", res);
  135. HighGui.waitKey();
  136. //! [draw final matches]
  137. System.exit(0);
  138. }
  139. }
  140. public class AKAZEMatchDemo {
  141. public static void main(String[] args) {
  142. // Load the native OpenCV library
  143. System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
  144. new AKAZEMatch().run(args);
  145. }
  146. }