Detecting an Object Using the OpenCV Function Threshold / Similarity Mapping - Java / C ++

I am creating a small program that detects objects (a small image) in a large image, and I use Java OpenCV. Since I have to consider rotation and scaling, I used FeatureDetector.BRISK and DescriptorExtractor.BRISK.

The following approach is used to filter match results for best matches.

I have two questions

  • Is there a way to find below min_dist and max_dist using the loop I used?
  • The most important question. Now the problem is that I need to use these matches to determine if an object (template) is found or not. It would be great if someone helped me here.

Thanks in advance.

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 that this is not the best way to conclude whether the found object is found or not based on the best matches. Therefore, 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; } 
+4
source share
2 answers

Your editable code works fine for me and works great,

The following are the changes I made in your code to detect objects (small image) in a large image:

  • using the SURF method to detect a function, as well as to extract a function. (SURF is available in opencv 4.1.1 for Android and earlier, after which it was removed from this, so here I used opencv 4.1.1)

  • change the threshold value of the image, mapped or not from 1 to 4, in the next line

    if (matchesFiltered.rows ()> = 1)

to

 if(matchesFiltered.rows() >= 4) 

only these changes worked fine for me, make sure the object / small image has a rich texture (at least there should be key points that can be matched)

+1
source

There are several approaches to detecting objects within images. Just post a few links here:

The last link shows how to calculate the values โ€‹โ€‹of min and max, should be almost the same in Java. All links should hopefully show some ideas on how to combine objects.

I also admitted there are a lot of magic numbers in your code. Perhaps you can put them in variables to reduce the chance of error and get a better overview.

0
source

All Articles