OpenCV滤波ORB匹配

9

我正在使用ORB特征检测器来寻找两张图片之间的匹配,使用以下代码:

    FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
    DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);;
    DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);

    // First photo
    Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGB2GRAY);
    Mat descriptors1 = new Mat();
    MatOfKeyPoint keypoints1 = new MatOfKeyPoint();

    detector.detect(img1, keypoints1);
    descriptor.compute(img1, keypoints1, descriptors1);

    // Second photo
    Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGB2GRAY);
    Mat descriptors2 = new Mat();
    MatOfKeyPoint keypoints2 = new MatOfKeyPoint();

    detector.detect(img2, keypoints2);
    descriptor.compute(img2, keypoints2, descriptors2);

    // Matching

    MatOfDMatch matches = new MatOfDMatch();
    MatOfDMatch filteredMatches = new MatOfDMatch();
    matcher.match(descriptors1, descriptors2, matches);

    // Linking
    Scalar RED = new Scalar(255,0,0);
    Scalar GREEN = new Scalar(0,255,0);

    List<DMatch> matchesList = matches.toList();
    Double max_dist = 0.0;
    Double min_dist = 100.0;

    for(int i = 0;i < matchesList.size(); i++){
        Double dist = (double) matchesList.get(i).distance;
        if (dist < min_dist)
            min_dist = dist;
        if ( dist > max_dist)
            max_dist = dist;
    }



    LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
    for(int i = 0;i < matchesList.size(); i++){
        if (matchesList.get(i).distance <= (1.5 * min_dist))
            good_matches.addLast(matchesList.get(i));
    }



    // Printing
    MatOfDMatch goodMatches = new MatOfDMatch();
    goodMatches.fromList(good_matches);

    System.out.println(matches.size() + " " + goodMatches.size());

    Mat outputImg = new Mat();
    MatOfByte drawnMatches = new MatOfByte();
    Features2d.drawMatches(img1, keypoints1, img2, keypoints2, goodMatches, outputImg, GREEN, RED, drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS);

    Highgui.imwrite("matches.png", outputImg);

我的问题是我找不到一种方法来过滤匹配项,使它们只在照片中具有相似的位置时匹配。即使它们在位置上非常远,我总是得到一个关键点的多个匹配项。
有没有更好的过滤方式?
3个回答

9
为了获得更好的匹配结果,您应该按照以下顺序包括这些过滤方法。
  1. 双向匹配:即对于第一张图片中的每个点,在第二张图片中找到最佳匹配,反之亦然。
  2. 执行比率测试(欧几里得距离比率测试)以消除模糊的匹配。
  3. 执行RANSAC测试:它是一种模型拟合算法,可以找到最适合模型的数据并去除异常值。
  4. 执行单应性变换:它是一种图像投影算法。
您可以在《计算机视觉应用编程食谱》的第9章中获取上述方法的所有详细信息。它还提供了实现这些过滤技术的示例代码。非常易于理解。 (注意:本书中的代码是C++,但一旦理解,也可以轻松实现JAVA)

1

在阅读Rober Langaniere的书后,我了解到有一种方法。它是通过删除距离更远的匹配项来实现的。在Java中,如下所示:

Collections.sort(bestMatches,new Comparator<DMatch>() {
        @Override
        public int compare(DMatch o1, DMatch o2) {
            if(o1.distance<o2.distance)
                return -1;
            if(o1.distance>o2.distance)
                return 1;
            return 0;
        }
    });
    if(bestMatches.size()>3){
        bestMatches = bestMatches.subList(0,3);
    }

嗨,谢谢你的回答,我也是用这种方法,在使用.match(..,..,..)方法获取原始匹配后,将它们按升序排序,然后选择前10、30或适合我的数量。我的问题是,将从.match(..,..,...)方法返回的匹配结果按升序排序是否可以替代阈值处理?因为我在许多示例中看到,当使用阈值处理时,似乎它是另一种获取最佳匹配的方式,并且使用您发布的排序算法可能是一种替代方法...请指教。 - rmaik
我认为更适合将其作为阈值的附加功能添加,这可以从好的匹配中过滤出最佳匹配。 - zawhtut
但是由于我已经按距离升序排列了,这意味着前10或15个将是其他距离中较小的那些,这意味着我选择了好的那些..请建议。 - rmaik
2
在他的书中,他没有使用阈值处理。但是对于细节部分,我还需要学习更多,因为我自己仍然不太理解该解决方案的“工作原理”部分。当我了解得更好时,我很愿意成为您的帮助。 - zawhtut

0

匹配是通过计算两个描述符之间的最短汉明距离来完成的。因此,您将始终在检测到的特征之间获得匹配。

您应该修改ORB检测器的阈值。这样,您将减少从背景(即噪声)中检测到的特征的可能性,因此大多数检测到的特征将来自感兴趣的主题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接