I'm trying to find out it two images are similar with openCV using image matching. I'm running the following code:
public static void match(String firstImage, String secondImage, String outputFile) {
FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
Mat firstImg = Imgcodecs.imread(firstImage, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
MatOfKeyPoint firstKeypoints = new MatOfKeyPoint();
Mat firstDescriptors = new Mat();
detector.detect(firstImg, firstKeypoints);
descriptor.compute(firstImg, firstKeypoints, firstDescriptors);
Mat secondImg = Imgcodecs.imread(secondImage, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
MatOfKeyPoint secondKeypoints = new MatOfKeyPoint();
Mat secondDescriptors = new Mat();
detector.detect(secondImg, secondKeypoints);
descriptor.compute(secondImg, secondKeypoints, secondDescriptors);
MatOfDMatch matches = new MatOfDMatch();
matcher.match(firstDescriptors, secondDescriptors, matches);
float minDis = Float.MAX_VALUE;
for (int i = 0;i < matches.rows();i++) {
if (matches.toArray()[i].distance < minDis)
minDis = matches.toArray()[i].distance;
}
LinkedList<DMatch> goodMatches = new LinkedList<>();
for (int i = 0;i < matches.rows();i++) {
if (matches.toArray()[i].distance < minDis*3)
goodMatches.add(matches.toArray()[i]);
}
List<Point> pts1 = new ArrayList<Point>();
List<Point> pts2 = new ArrayList<Point>();
for(int i = 0; i<goodMatches.size(); i++){
pts1.add(firstKeypoints.toList().get(goodMatches.get(i).queryIdx).pt);
pts2.add(secondKeypoints.toList().get(goodMatches.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);
Calib3d.findHomography(pts1Mat, pts2Mat, Calib3d.RANSAC, 15, outputMask, 2000, 0.995);
// outputMask contains zeros and ones indicating which matches are filtered
LinkedList<DMatch> betterMatches = new LinkedList<DMatch>();
for (int i = 0; i < goodMatches.size(); i++) {
if (outputMask.get(i, 0)[0] != 0.0) {
betterMatches.add(goodMatches.get(i));
}
}
Mat outputImg = new Mat();
MatOfDMatch betterMatchesMat = new MatOfDMatch();
betterMatchesMat.fromList(betterMatches);
Features2d.drawMatches(firstImg, firstKeypoints, secondImg, secondKeypoints, betterMatchesMat, outputImg);
Imgcodecs.imwrite(outputFile, outputImg);
}
When the images are similar the result looks like:
When the images are not similar the result looks like:
You can see that in the first case the match lines are parallel so it makes sense that the two images are similar. In the second case the match lines are not parallel so it makes sense that the images are not similar. Is there a standard way to analyse these matches and to find in which case the images are most probably similar?