How to check if two images are similar or not using openCV in java?

后端 未结 2 1993
借酒劲吻你
借酒劲吻你 2021-02-03 10:49

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(         


        
2条回答
  •  清酒与你
    2021-02-03 11:46

    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 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 good_matches = new LinkedList();
    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 objList = new LinkedList();
            LinkedList sceneList = new LinkedList();
    
            List keypoints_RefList = keypointsRef.toList();
            List 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.

提交回复
热议问题