Java OpenCV - 从knnMatch中提取好匹配 [英] Java OpenCV - extracting good matches from knnMatch

查看:140
本文介绍了Java OpenCV - 从knnMatch中提取好匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to implement a very simple program for finding similarities between two images.

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

I am using the ORB feature detector and image descriptor for this task and I am identifying the matches using 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<MatOfDMatch> matches = new ArrayList<MatOfDMatch>();
matcher.knnMatch(descriptors1, descriptors2, matches, 5);

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

I am able to draw the matches as follows:

// 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);

问题在于匹配太多,而且还包括那些远离的匹配。我似乎无法找到如何只提取好的匹配(超过一些阈值)?有人能指出我正确的方向或将我重定向到一些基本的工作示例吗?我花了好几个小时就好了,似乎迷路了......

The problem is that there are too many matches and it includes also those that are way off. I can't seem to find how to extract only the good matches (exceeding some threshold)? Could someone point me to the right direction or redirect me to some basic working example? I have spent several hours on this and seem to be lost..

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

I tried looking at Keypoint matching just works two times...? (java opencv) but the standard (non-knn) match uses different structures and and I could not make it work.

推荐答案

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

As mentioned in other answers, there are several methods to remove outliers and bad matches. I guess you found samples and tutorials with match instead of knnMatch utilizing some of those methods.

所以,你可能知道区别在于 knnMatch 返回<$ c $中的n个最佳匹配c> descriptor2 为 descriptor1 中的每个描述符。这意味着,您将获得匹配列表,而不是匹配列表。我想这就是你遇到问题的原因。

So, as you may know the difference is that knnMatch returns the n-best matches in descriptor2 for each descriptor in descriptor1. Which means, instead of a list of matches you get a list of a list of matches. I guess this is the reason, why you had problems.

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

The main advantage using knnMatch is that you can perform a ratio test. So if the distances from one descriptor in descriptor1 to the two best descriptors in descriptor2 are similar it suggests that there are repetitive patterns in your images (e.g. the tips of a picket fence in front of grass). Thus, such matches aren't reliable and should be removed. (I am not sure why you search for the five best matches - you pass 5 to knnMatch - for each descriptor. Rather search for two.)

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

If you now want to access the best match just for each descriptor, you just have to access the first element of the "sublists". In the following you'll find as a example a ratio test and a homography estimation using RANSAC (I replaced everything after your knnMatch):

    // ratio test
    LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
    for (Iterator<MatOfDMatch> 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<Point> pts1 = new ArrayList<Point>();
    List<Point> pts2 = new ArrayList<Point>();
    for(int i = 0; i<good_matches.size(); i++){
        pts1.add(keypoints1.toList().get(good_matches.get(i).queryIdx).pt);
        pts2.add(keypoints2.toList().get(good_matches.get(i).trainIdx).pt);
    }

    // convertion of data types - there is maybe a more beautiful way
    Mat outputMask = new Mat();
    MatOfPoint2f pts1Mat = new MatOfPoint2f();
    pts1Mat.fromList(pts1);
    MatOfPoint2f pts2Mat = new MatOfPoint2f();
    pts2Mat.fromList(pts2);

    // Find homography - here just used to perform match filtering with RANSAC, but could be used to e.g. stitch images
    // the smaller the allowed reprojection error (here 15), the more matches are filtered 
    Mat Homog = Calib3d.findHomography(pts1Mat, pts2Mat, Calib3d.RANSAC, 15, outputMask, 2000, 0.995);

    // outputMask contains zeros and ones indicating which matches are filtered
    LinkedList<DMatch> better_matches = new LinkedList<DMatch>();
    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);

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

I hope this is sufficient as a example. Other filtering methods could be applied analogously. Do not hesitate to ask, if you have further questions.

编辑:
单应性过滤仅在大多数情况下有效关键点位于场景的同一平面上,如墙等。

The homography filtering is only valid if most of your keypoints are on the same plane in the scene, like a wall etc.

这篇关于Java OpenCV - 从knnMatch中提取好匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆