Compute Two Images Similarity Using Python OpenCV and SIFT – Python OpenCV Tutorial

By | August 1, 2022

When we are comparing two images, we have to compute the similarity score between them. In this tutorial, we will compute its similarity score using python opencv sift.

How to use opencv SIFT?

In order to use sift in opencv, we have to use python opencv 3.4.2.16. Otherwise, you will get AttributeError: module ‘cv2’ has no attribute ‘xfeatures2d’ error.

Fix AttributeError: module ‘cv2’ has no attribute ‘xfeatures2d’ – Python OpenCV Tutorial

How to compute the similarity score between two images?

Here we will give you a full example code to compute.

import cv2
import matplotlib.pyplot as plt

# Resize images to a similar dimension
# This helps improve accuracy and decreases unnecessarily high number of keypoints

def imageResizeTrain(image):
    maxD = 1024
    height,width = image.shape
    aspectRatio = width/height
    if aspectRatio < 1:
        newSize = (int(maxD*aspectRatio),maxD)
    else:
        newSize = (maxD,int(maxD/aspectRatio))
    image = cv2.resize(image,newSize)
    return image

def imageResizeTest(image):
    maxD = 1024
    height,width,channel = image.shape
    aspectRatio = width/height
    if aspectRatio < 1:
        newSize = (int(maxD*aspectRatio),maxD)
    else:
        newSize = (maxD,int(maxD/aspectRatio))
    image = cv2.resize(image,newSize)
    return image

def computeSIFT(image):
    sift = cv2.xfeatures2d.SIFT_create()
    return sift.detectAndCompute(image, None)


def calculateResultsFor(image_1,image_2):

    image_1_data = imageResizeTrain(cv2.imread(image_1,0))
    image_2_data = imageResizeTrain(cv2.imread(image_2, 0))
    keypoint1, descriptor1 = computeSIFT(image_1_data)
    keypoint2, descriptor2 = computeSIFT(image_2_data)

    matches = calculateMatches(descriptor1, descriptor2)
    score = calculateScore(len(matches),len(keypoint1),len(keypoint2))
    plot = getPlotFor(image_1,image_2,keypoint1,keypoint2,matches)
    #print(len(matches),len(keypoint1),len(keypoint2),len(descriptor1),len(descriptor2))
    #print(score) # 结果
    plt.imshow(plot),plt.show()
    return score

def getPlotFor(image1,image2,keypoint1,keypoint2,matches):
    image1 = imageResizeTest(cv2.imread(image1))
    image2 = imageResizeTest(cv2.imread(image2))
    return getPlot(image1,image2,keypoint1,keypoint2,matches)

def calculateScore(matches,keypoint1,keypoint2):
    return 100 * (matches/min(keypoint1,keypoint2))


def calculateMatches(des1, des2):
    bf = cv2.BFMatcher()
    matches = bf.knnMatch(des1, des2, k=2)
    topResults1 = []
    for m, n in matches:
        if m.distance < 0.7 * n.distance:
            topResults1.append([m])

    matches = bf.knnMatch(des2, des1, k=2)
    topResults2 = []
    for m, n in matches:
        if m.distance < 0.7 * n.distance:
            topResults2.append([m])

    topResults = []
    for match1 in topResults1:
        match1QueryIndex = match1[0].queryIdx
        match1TrainIndex = match1[0].trainIdx

        for match2 in topResults2:
            match2QueryIndex = match2[0].queryIdx
            match2TrainIndex = match2[0].trainIdx

            if (match1QueryIndex == match2TrainIndex) and (match1TrainIndex == match2QueryIndex):
                topResults.append(match1)
    return topResults

def getPlot(image1,image2,keypoint1,keypoint2,matches):
    image1 = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)
    image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2RGB)
    matchPlot = cv2.drawMatchesKnn(image1,keypoint1,image2,keypoint2,matches,None,[255,255,255],flags=2)
    return matchPlot

#--

imageList = [
r"C:\Users\yuzhilun\Desktop\book_cover\1.png",
r"C:\Users\yuzhilun\Desktop\book_cover\2.png",
r"C:\Users\yuzhilun\Desktop\book_cover\3.png",
r"C:\Users\yuzhilun\Desktop\book_cover\4.png"]
lx = len(imageList) -1
for i in range(lx):
    score = calculateResultsFor(imageList[i],imageList[i+1])
    print(imageList[i],imageList[i+1],score)

In this example, we will use calculateResultsFor() function to compute the similarity score between two image. This function will receive two images and return their similarity score.

Run this code, we will see:

C:\Users\yuzhilun\Desktop\book_cover\1.png C:\Users\yuzhilun\Desktop\book_cover\2.png 0.125
C:\Users\yuzhilun\Desktop\book_cover\2.png C:\Users\yuzhilun\Desktop\book_cover\3.png 0.1875
C:\Users\yuzhilun\Desktop\book_cover\3.png C:\Users\yuzhilun\Desktop\book_cover\4.png 0.1405152224824356

Compute Two Images Similarity Using Python OpenCV and SIFT - Python OpenCV Tutorial

From the result, we can find:if the score is low, these two images are different.