Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing two images with OpenCV in Java

Tags:

java

opencv

I am trying to compare two images (determine whether they are similar or not) using the OpenCV library. I configured the java wrapper and found several tutorials (mostly in C/C++) that I am trying to rewrite into Java. I am using the feature detection approach.

The problem is that the algorithm that I currently have does not produce any reasonable results (it claims that two similar images have nothing in common and finds matches between other two images that are completely different). Could someone suggest how should I use the openCV matcher to produce some reasonable results?

This is my code for the image comparison

private static void compareImages(String path1, String path2) {
    System.out.println(path1 + "-" + path2);

    FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
    DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);

    DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);

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

    // match these two keypoints sets
    MatOfDMatch matches = new MatOfDMatch();
    matcher.match(descriptors1, descriptors2, matches);

    for (DMatch m : matches.toArray()) {
      // how to use these values to detect the similarity? They seem to be way off
      // all of these values are in range 50-80 which seems wrong to me
      System.out.println(m.distance);
    }
  }

Unfortunately, algorithms like SURF and SIFT are not available in the java wrapper so I am using ORB. I have little to no experience with computer vision, I am just trying to get this simple comparison algorithm work to produce some reasonable outcome. I would be glad for any help!

EDIT: My use-case is running this algorithm against images taken from different angles. I updated my code to be better formatted.

Sample images to compare:

enter image description here enter image description here

like image 561
Smajl Avatar asked Jan 13 '16 09:01

Smajl


1 Answers

Just my two cents:

  1. There is access to SURF and SIFT in java: openCV DescriptorExtractor Reference. I tried the FREAK implementation three years back and found out, that there is some change happening to the binary descriptor when openCV passes them over to Java. It may be that ORB is subject to the same problem. Did you compare the data of the descriptors from c or c++ to the ones on the java side?

  2. The brute force matcher finds the best matching feature from the train image for EVERY feature in the query image. Even if it looks completely different. You have to sift through the matches and drop bad ones. There exist several strategies, an easy one would be to just take the best 20% of the matches (but this will not drop ALL outlier). Progressive Sample Consensus performed very well in my setup.

  3. Using Features to compare image similarity has it's pitfalls. Feature count and quality are varying with picture size and content, which makes it difficult to compare images globally (in case you wanna know which of two images is more similar to a reference than the other). You could estimate a transform from one image to the other with Calib3d.findHomography(obj, scene, CV_RANSAC); and use a normalized pixel difference of the overlapping areas.
like image 69
Gilfoyle Avatar answered Oct 21 '22 12:10

Gilfoyle