I have to check if two images are similar or not in java using OpenCV, I am using OpenCV for that and using ORB
Here is my main class
System.out.println(
Matcher only search for nearest match of keypoints graph. For measure difference you need use (average) sum (or other metric) of distances.
Since you are using BRUTEFORCE matcher you will always get best possible matches for all the keypoint descriptors from your query(template) in your train(image that contains query). i.e: BRUTEFORCE matcher will always find 100% matches(best equivalent keypoints for all query keypoint descriptors in train descriptors).
This means you need to filter the matches as correct matches(inliers) and incorrect matches(outliers) matches.
You can do it in two ways
1.Distance calculation
Using distance as mentioned by Andrey Smorodov. You can use this method (But this does not always provide correct results)
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 <= (3 * min_dist)) // change the limit as you desire
good_matches.addLast(matchesList.get(i));
}
2.Determine Mask
You can use the findHomography to get the mask which lets you find the inliers and outliers clearly(Since it considers into account camera pose perspective it is almost correct)
LinkedList<Point> objList = new LinkedList<Point>();
LinkedList<Point> sceneList = new LinkedList<Point>();
List<KeyPoint> keypoints_RefList = keypointsRef.toList();
List<KeyPoint> keypoints_List = keypoints.toList();
for (int i = 0; i < good_matches.size(); i++) {
objList.addLast(keypoints_RefList.get(good_matches.get(i).queryIdx).pt);
sceneList.addLast(keypoints_List.get(good_matches.get(i).trainIdx).pt);
}
MatOfPoint2f obj = new MatOfPoint2f();
MatOfPoint2f scene = new MatOfPoint2f();
obj.fromList(objList);
scene.fromList(sceneList);
Mat mask = new Mat();
Mat hg = Calib3d.findHomography(obj, scene, 8, 10, mask);
Now the mask is an optional output in findHomography which is a array of either 1 or 0 value each for every match. The mask value for corresponding match is 1 if it is an inlier and 0 if it is an outlier.
You may use this as a criteria to decide if you have almost 90% of mask to be 1 then you can have the output to be true.
I use it in recognizing specific objects from android java camera frame and got these log results
08-22 01:08:38.929: I/OCVSample::Activity(25799): Keypoints Size: 1x477 KeypointsRef Size : 1x165
08-22 01:08:39.049: I/OCVSample::Activity(25799): descriptor Size: 32x477 descriptorRef Size : 32x165
08-22 01:08:39.129: I/OCVSample::Activity(25799): Matches Size: 1x165
08-22 01:08:39.129: I/OCVSample::Activity(25799): matchesList Size: 165
08-22 01:08:39.139: I/OCVSample::Activity(25799): Max dist : 460.44110107421875 Min dist : 100.0
08-22 01:08:39.139: I/OCVSample::Activity(25799): good matches size: 19
08-22 01:08:39.139: I/OCVSample::Activity(25799): obj size : 1x165
08-22 01:08:39.139: I/OCVSample::Activity(25799): scene size : 1x165
08-22 01:08:40.239: I/OCVSample::Activity(25799): Homography mask size : 1x165
08-22 01:08:40.239: I/OCVSample::Activity(25799): Homography mask : [1; 1; 1; 1; 1; 1; 1; 0; 1; 0; 1; 1; 1; 1; 0; 1; 1; 1; 0; 1; 1; 1; 1; 0; 1; 0; 1; 1; 1; 1; 1; 1; 0; 0; 1; 1; 1; 1; 0; 1; 0; 1; 1; 1; 1; 1; 0; 1; 1; 1; 1; 1; 1; 1; 0; 1; 1; 0; 1; 0; 1; 0; 0; 1; 0; 1; 1; 1; 1; 1; 1; 1; 0; 1; 1; 1; 1; 1; 0; 1; 1; 1; 1; 0; 0; 1; 1; 0; 1; 1; 1; 1; 0; 1; 0; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 0; 1; 1; 1; 1; 0; 0; 0; 1; 0; 1; 1; 1; 1; 0; 0; 1; 1; 1; 1; 1; 0; 1; 0; 1; 1; 0; 1; 0; 1; 1; 1; 1; 1; 1; 0; 1; 1; 0; 1; 1; 1; 1; 0; 1; 1; 1; 1; 1; 1; 1; 0; 1; 1; 0; 0; 1; 1]
3. Yet another simpler approach would be comparing the histogram of those two images for this you can use compHist(); function of openCV as shown here and also refer openCV documents.
Various methods in compare histogram gives output range from 0 to 1 or higher value, this output depends on similarity between histograms. Careful in some methods 1 is 100% positive match and 0 in some other method. "For chi-square method a low score represents a better match than a high score. A perfect match is 0 and a total mismatch is unbounded (depending on the size of the histogram)."
Remainder:- Two completely different images can have exactly the same histogram value.
Tips:
1.Now regarding knnMatch just use matcher.knnMatch(); and the appropriate datatypes for output.
2.Also in
matcher.match(query, train, matches);
the query => keypoint descriptors for template-eg. a ball and
the train => keypoint descriptor for image that contains the same ball in it. The no of query descriptor is less than no of train descriptor make sure you get this right.
Now good luck.