View on GitHub

comparing_images

Compare the objects in the two images and spot the difference

Week 5

Comparing Descriptor Matching Algorithms and Options

Introduction

This week’s blog will contain a comparison between BFMatcher and FLANN. It will also compare the results from changing some of the parameters in BFMatcher. The descriptors used were generated from the AKAZE algorithm for feature detection as it provided the best results.

Brute-Force Matching (BFMatcher)

This method takes each feature from one of the descriptors and compares it to all the other features in the second one. It returns the matching feature with minimal distance.

BFMatcher with and without Cross Checking

The BFMatcher object takes two parameters: a normType and a boolean crossCheck. The first one is used to specify which type of distance measuring algorithm to use, such as: NORM_HAMMING, NORM_HAMMING2, NORM_L1, NORM_L2. The second parameter parameter is used to toggle Cross Checking. If it’s true, then for any pair (i, j) found matching it will also check if it’s true for (j, i). This means that enabling Cross Checking allows for a more consistent feature matching.

Code

def bfmatcher(window, img1, kp1, desc1, img2, kp2, desc2, normType = cv2.NORM_HAMMING, crossCheck = True, noMatches = 250):
    bf = cv2.BFMatcher(normType = normType, crossCheck = crossCheck)
    matches = bf.match(desc1, desc2)
    matches = sorted(matches, key = lambda x:x.distance)
    matchesImage = np.zeros(shape=(1,1))
    matchesImage = cv2.drawMatches(img1 = img1, keypoints1 = kp1, img2 = img2, keypoints2 = kp2, matches1to2 = matches[:noMatches], outImg = matchesImage, flags=2)

    cv2.imwrite('BFMatcher.jpg', matchesImage)
    cv2.imshow('BFMatcher', matchesImage)
    cv2.waitKey(0)

BFMatcher using the Ratio Test

A Ratio Test can also be used instead of Cross Cheking to check if the match is correct. This was proposed by D.Lowe[1] as a way of only getting correct matches for the SIFT algorithm, but it can also be used for AKAZE descriptors. For this, a modified function than the one above was used, which uses knnMatcher to get the best two matches of a feature. The match is only considered correct if the distance between the best two matches is more than 25%.

Code

def bfmatcherknn(window, img1, kp1, desc1, img2, kp2, desc2, normType = cv2.NORM_HAMMING, k = 2, noMatches = 250):
    bf = cv2.BFMatcher(normType = normType)
    matches = bf.knnMatch(desc1, desc2, k = 2)

    # Use D.Lowe's Ratio Test
    if k == 2:
        bestMatches = []
        for match1, match2 in matches:
            if match1.distance < 0.75 * match2.distance:
                bestMatches.append([match1])
        matches = bestMatches

    matchesImage = np.zeros(shape=(1,1))
    matchesImage = cv2.drawMatchesKnn(img1 = img1, keypoints1 = kp1, img2 = img2, keypoints2 = kp2, matches1to2 = matches[:noMatches], outImg = matchesImage, flags=2)

    cv2.imwrite('BFMatcherknn.jpg', matchesImage)
    cv2.imshow('BFMatcherknn', matchesImage)
    cv2.waitKey(0)

Comparing several Distance Measuring Algorithms

NORM_HAMMING

Uses Hamming Distance to measure the distance between features.

w/o Cross Checking
w/ Cross Checking
w/ Ratio Test

NORM_HAMMING2

Uses a modified Hamming Distance Algorithm to measure the distance between features. It’s usually used for feature detection using ORB.

w/o Cross Checking
w/ Cross Checking
w/ Ratio Test

NORM_L1

Uses the Manhattan Distance to measure the distance between features.

w/o Cross Checking
w/ Cross Checking
w/ Ratio Test

NORM_L2

Uses Euclidian Distance to measure the distance between features.

w/o Cross Checking
w/ Cross Checking
w/ Ratio Test

All four algorithms for measuring distance provide similar results with NORM_HAMMING and NORM_L1 giving the best results. For binary based descriptors (such as AKAZE’s descriptors), the OpenCV documentation recommends using NORM_HAMMING[2]. The images above also showed that Cross Checking provides better results, and the Ratio Test provides even better results in the best 250 matches.

Comparing Cross Checking and Ratio Test on all the matches using NORM_HAMMING

Cross Checking Ratio Test

When all the feature matches are displayed, the Ratio Test only shows a small number of similarities where Cross Checking found a lot more. While the Ratio Test whould be better for finding objects from one image in another, this project tries to find the differences between the images, so the algorithm that finds the most similarities whould be a better candidate for the project.

Fast Approximate Nearest Neighbor Search Matching (FLANN)

Another feature matching algorithm is FLANN. This uses nearest neighbours searching to find the best matches. It’s a faster way of detecting matching features between two object than Brute-Force Matching. It was proposed by M.Muja and D.Lowe [3].

Code

def flannmatcher(window, img1, kp1, desc1, img2, kp2, desc2, flannIndex = 0, trees = 5, checks = 50, noMatches = 250):
    indexParams = dict(algorithm = flannIndex, trees = trees)
    searchParams = dict(checks = 50)

    flann = cv2.FlannBasedMatcher(indexParams, searchParams)

    # Convert descriptors to CV_32F
    desc1 = np.float32(desc1)
    desc2 = np.float32(desc2)

    matches = flann.knnMatch(desc1, desc2, k = 2)

    # Use D.Lowe's Ratio Test
    mask = []
    matchIndex = 0
    for match1, match2 in matches:
        if matchIndex == noMatches:
            break
        matchIndex += 1
        if match1.distance < 0.75 * match2.distance:
            mask.append([1, 0])
        else:
            mask.append([0, 0])

    drawParams = dict(matchColor = (0, 0, 255), singlePointColor = (255, 0, 0), matchesMask = mask, flags = 0)

    matchesImage = np.zeros(shape=(1,1))
    matchesImage = cv2.drawMatchesKnn(img1 = img1, keypoints1 = kp1, img2 = img2, keypoints2 = kp2, matches1to2 = matches[:noMatches], outImg = matchesImage, **drawParams)

    cv2.imwrite('FLANN.jpg', matchesImage)
    cv2.imshow('FLANN', matchesImage)
    cv2.waitKey(0)

Comparing FLANN with BFMatcher

FLANN BFMatcher

FLANN provides similar results to the BFMatcher algorithm using the Ratio Test. While the matches are excellent, there are not enough matches to be able to then find the differences between the images.

Conclusion

From all the test, the Brute-Force Matching algorithm using NORM_HAMMING and Cross Checking provided the best results for the next step of the project. This algorithm may have to be limited to only a subset of the best results as the last matches that BFMatcher provided seem to point completely in the wrong place.

References

[1] D.Lowe, ‘Distinctive Image Features from Scale-Invariant Keypoints’, International Journal of Computer Vision, Vol. 60, Issue 2, 2004, pp. 91-110

[2] ‘OpenCV 3.0-beta feature2d Tutorials’, 2014, [Online]. Available: https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_matcher/py_matcher.html. [Accessed: 2017-10-14]

[3] M.Muja and D.Lowe, ‘Fast Approximate Nearest Neighbors with Automatic Algorithm Configuration’, VISAPP International Conference on Computer Vision Theory and Applications, 2009