Java OpenCV – 从knnMatch中提取好匹配

我正在尝试实现一个非常简单的程序来查找两个图像之间的相似性。

我正在使用ORBfunction检测器和图像描述符执行此任务,我使用knnMatch识别匹配:

FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB); DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB); DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING); // DETECTION // first image Mat img1 = Imgcodecs.imread(path1, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE); Mat descriptors1 = new Mat(); MatOfKeyPoint keypoints1 = new MatOfKeyPoint(); detector.detect(img1, keypoints1); descriptor.compute(img1, keypoints1, descriptors1); // second image Mat img2 = Imgcodecs.imread(path2, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE); Mat descriptors2 = new Mat(); MatOfKeyPoint keypoints2 = new MatOfKeyPoint(); detector.detect(img2, keypoints2); descriptor.compute(img2, keypoints2, descriptors2); // MATCHING // match these two keypoints sets List matches = new ArrayList(); matcher.knnMatch(descriptors1, descriptors2, matches, 5); 

我可以按如下方式绘制匹配项:

 // DRAWING OUTPUT Mat outputImg = new Mat(); // this will draw all matches, works fine Features2d.drawMatches2(img1, keypoints1, img2, keypoints2, matches, outputImg); // save image Imgcodecs.imwrite("result.jpg", outputImg); 

问题是有太多的匹配,它也包括那些离开的。 我似乎无法找到如何只提取好的匹配(超过一些阈值)? 有人能指出我正确的方向或将我重定向到一些基本的工作示例吗? 我已经花了几个小时在这上面,似乎迷路了……

编辑:

我试过看Keypoint匹配工作两次……? (java opencv)但标准(非knn)匹配使用不同的结构,我无法使其工作。

正如其他答案中所提到的,有几种方法可以删除exception值和不匹配。 我猜你使用其中一些方法找到了match而不是knnMatch样本和教程。

因此,您可能知道不同之处在于knnMatch为descriptor1中的每个描述descriptor1返回knnMatch的n个最佳匹配。 这意味着,您将获得匹配列表,而不是匹配列表。 我想这就是为什么你有问题的原因。

使用knnMatch的主要优点是您可以执行比率测试。 因此,如果描述descriptor1 1中的一个描述descriptor1到描述descriptor1中的两个最佳描述descriptor2距离相似,则表明图像中存在重复模式(例如草前栅栏的尖端)。 因此,这种匹配不可靠,应予以删除。 (我不确定你为什么要搜索五个最佳匹配 – 你为每个描述符传递5到knnMatch 。而是搜索两个。)

如果您现在只想为每个描述符访问最佳匹配,则只需访问“子列表”的第一个元素。 在下文中,您将找到使用RANSAC进行比率测试和单应性估计的示例(我在您的knnMatch之后替换了所有内容):

  // ratio test LinkedList good_matches = new LinkedList(); for (Iterator iterator = matches.iterator(); iterator.hasNext();) { MatOfDMatch matOfDMatch = (MatOfDMatch) iterator.next(); if (matOfDMatch.toArray()[0].distance / matOfDMatch.toArray()[1].distance < 0.9) { good_matches.add(matOfDMatch.toArray()[0]); } } // get keypoint coordinates of good matches to find homography and remove outliers using ransac List pts1 = new ArrayList(); List pts2 = new ArrayList(); for(int i = 0; i better_matches = new LinkedList(); for (int i = 0; i < good_matches.size(); i++) { if (outputMask.get(i, 0)[0] != 0.0) { better_matches.add(good_matches.get(i)); } } // DRAWING OUTPUT Mat outputImg = new Mat(); // this will draw all matches, works fine MatOfDMatch better_matches_mat = new MatOfDMatch(); better_matches_mat.fromList(better_matches); Features2d.drawMatches(img1, keypoints1, img2, keypoints2, better_matches_mat, outputImg); // save image Imgcodecs.imwrite("result.jpg", outputImg); 

我希望这足以作为一个例子。 其他过滤方法可以类似地应用。 如果您有其他问题,请随时询问。

编辑:单应性滤波仅在大多数关键点位于场景中的同一平面上时才有效,如墙壁等。