使用具有阈值/相似性分数的 OpenCV 特征匹配进行对象检测 - Java/C++ [英] Object detection with OpenCV Feature Matching with a threshold/similarity score - Java/C++

查看:29
本文介绍了使用具有阈值/相似性分数的 OpenCV 特征匹配进行对象检测 - Java/C++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个小程序来检测大图像中的对象(小图像),我正在使用 OpenCV java.因为我必须考虑旋转和缩放,所以我使用了 FeatureDetector.BRISK 和 DescriptorExtractor.BRISK.

I am in the process of creating a small program which detects objects(small image) in the large image and I am using OpenCV java. As I have to consider rotation and scaling I have used FeatureDetector.BRISK and DescriptorExtractor.BRISK.

以下方法用于过滤匹配结果以获得最佳匹配.

Following approach is used to filter the match results to get the best matches only.

我有两个问题

  1. 有没有办法用我使用的循环找到下面的 min_dist 和 max_dist?
  2. 最重要的问题 - 现在的问题是我需要使用这些匹配来确定是否找到了对象(模板).如果有人在这里帮助我,那就太好了.

提前致谢.

    FeatureDetector  fd = FeatureDetector.create(FeatureDetector.BRISK); 
    final MatOfKeyPoint keyPointsLarge = new MatOfKeyPoint();
    final MatOfKeyPoint keyPointsSmall = new MatOfKeyPoint();

    fd.detect(largeImage, keyPointsLarge);
    fd.detect(smallImage, keyPointsSmall);

    System.out.println("keyPoints.size() : "+keyPointsLarge.size());
    System.out.println("keyPoints2.size() : "+keyPointsSmall.size());

    Mat descriptorsLarge = new Mat();
    Mat descriptorsSmall = new Mat();

    DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRISK);
    extractor.compute(largeImage, keyPointsLarge, descriptorsLarge);
    extractor.compute(smallImage, keyPointsSmall, descriptorsSmall);

    System.out.println("descriptorsA.size() : "+descriptorsLarge.size());
    System.out.println("descriptorsB.size() : "+descriptorsSmall.size());

    MatOfDMatch matches = new MatOfDMatch();

    DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMINGLUT);
    matcher.match(descriptorsLarge, descriptorsSmall, matches);

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

    MatOfDMatch matchesFiltered = new MatOfDMatch();

    List<DMatch> matchesList = matches.toList();
    List<DMatch> bestMatches= new ArrayList<DMatch>();

    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 && dist != 0)
        {
            min_dist = dist;
        }

        if (dist > max_dist)
        {
            max_dist = dist;
        }

    }

    System.out.println("max_dist : "+max_dist);
    System.out.println("min_dist : "+min_dist);

    double threshold = 3 * min_dist;
    double threshold2 = 2 * min_dist;

    if (threshold2 >= max_dist)
    {
        threshold = min_dist * 1.1;
    }
    else if (threshold >= max_dist)
    {
        threshold = threshold2 * 1.4;
    }

    System.out.println("Threshold : "+threshold);

    for (int i = 0; i < matchesList.size(); i++)
    {
        Double dist = (double) matchesList.get(i).distance;
        System.out.println(String.format(i + " match distance best : %s", dist));
        if (dist < threshold)
        {
            bestMatches.add(matches.toList().get(i));
            System.out.println(String.format(i + " best match added : %s", dist));
        }
    }


    matchesFiltered.fromList(bestMatches);

    System.out.println("matchesFiltered.size() : " + matchesFiltered.size());

<小时>

编辑

按如下方式编辑我的代码.我知道这仍然不是根据最佳匹配项是否找到对象来得出结论的最佳方法.所以请分享您的观点.


Edit

Edited my code as follows.I know still it's not the best way to come to a conclusion whether the object found or not based on no of best matches. So please share your views.

    System.out.println("max_dist : "+max_dist);
    System.out.println("min_dist : "+min_dist);

    if(min_dist > 50 )
    {
        System.out.println("No match found");
        System.out.println("Just return ");
        return false;
    }

    double threshold = 3 * min_dist;
    double threshold2 = 2 * min_dist;

    if (threshold > 75)
    {
        threshold  = 75;
    }
    else if (threshold2 >= max_dist)
    {
        threshold = min_dist * 1.1;
    }
    else if (threshold >= max_dist)
    {
        threshold = threshold2 * 1.4;
    }

    System.out.println("Threshold : "+threshold);

    for (int i = 0; i < matchesList.size(); i++)
    {
        Double dist = (double) matchesList.get(i).distance;

        if (dist < threshold)
        {
            bestMatches.add(matches.toList().get(i));
            //System.out.println(String.format(i + " best match added : %s", dist));
        }
    }

    matchesFiltered.fromList(bestMatches);

    System.out.println("matchesFiltered.size() : " + matchesFiltered.size());


    if(matchesFiltered.rows() >= 1)
    {
        System.out.println("match found");
        return true;
    }
    else
    {
        return false;
    }

推荐答案

你编辑的代码对我来说很好用,而且工作得很好,

Your Edited code is working fine for me, and working perfectly,

以下是我在您的代码中为检测大图像中的对象(小图像)所做的更改:

Following are changes that i have done in your code for detecting objects(small image) in the large image :

  1. 使用 SURF 方法进行特征检测和特征提取.(SURF 在 Android 及更早版本的 opencv 4.1.1 中可用,之后它已从中删除,所以在这里我使用了 opencv 4.1.1)

  1. using SURF method for feature detection as well as feature extraction.(SURF is available in opencv 4.1.1 for Android and earlier, after that it have been removed from that, so here i have used opencv 4.1.1)

将图像匹配或不匹配的阈值从 1 更改为 4,如下行

change threshold of image matched or not from 1 to 4, in following line

if(matchesFiltered.rows() >= 1)

if(matchesFiltered.rows() >= 1)

if(matchesFiltered.rows() >= 4)

只有这个改动对我来说很完美,确保物体/小图像具有丰富的纹理(至少应该有可以匹配的关键点)

only this changes have worked perfectly for me, make sure that object/small image have rich texture(atleast should have keypoints that can be matched)

这篇关于使用具有阈值/相似性分数的 OpenCV 特征匹配进行对象检测 - Java/C++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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