12

There are many questions over here which checks if two images are "nearly" similar or not.

My task is simple. With OpenCV, I want to find out if two images are 100% identical or not.

They will be of same size but can be saved with different filenames.

Hadi
  • 5,328
  • 11
  • 46
  • 67
milan m
  • 2,164
  • 3
  • 26
  • 40
  • Which language are you programming in? – Hadi Apr 21 '14 at 14:21
  • If you are really interested in the "fastest" method (as the title indicates), it might be useful to have some more background-information like: how often are the images assumed to be equal. for example if you expect many non-equaling images, you might be able to detect non-equaling imaging very fast, while equaling images may need some more time since they occur seldom – Micka Apr 22 '14 at 08:43
  • @Micka, Given a folder, identify all the duplicates. That is the functionality required. – milan m Apr 22 '14 at 12:18
  • by "fastest method" you mean "fastest/easiest to implement" or "shortest processing time"? – Micka Apr 22 '14 at 12:53
  • @Micka, shortest processing time. It is the main reason why I am trying to do it using OpenCV. – milan m Apr 22 '14 at 13:15
  • if the images are in a large resolution, you can subsample them first and only continue comparison on finer level if subsampling was identical. If the binary FILES are duplicates, there might be faster ways than creating images, but that will fail if the images are tagged differently for example or use different lossless compression techniques. Fastest decline for non-duplicates might be to compare only n random pixel positions before comparing the whole images. – Micka Apr 22 '14 at 13:40
  • @Micka, sorry but didnt understand you. can you please post the code. – milan m Apr 22 '14 at 18:15

7 Answers7

15

You can use a logical operator like xor operator. If you are using python you can use the following one-line function:

Python

def is_similar(image1, image2):
    return image1.shape == image2.shape and not(np.bitwise_xor(image1,image2).any())

where shape is the property that shows the size of matrix and bitwise_xor is as the name suggests. The C++ version can be made in a similar way!

C++

Please see @berak code.


Notice: The Python code works for any depth images(1-D, 2-D, 3-D , ..), but the C++ version works just for 2-D images. It's easy to convert it to any depth images by yourself. I hope that gives you the insight! :)

Doc: bitwise_xor

EDIT: C++ was removed. Thanks to @Micka and @ berak for their comments.

Hadi
  • 5,328
  • 11
  • 46
  • 67
9

the sum of the differences should be 0 (for all channels):

bool equal(const Mat & a, const Mat & b)
{
    if ( (a.rows != b.rows) || (a.cols != b.cols) )
        return false;
    Scalar s = sum( a - b );
    return (s[0]==0) && (s[1]==0) && (s[2]==0);
}
berak
  • 39,159
  • 9
  • 91
  • 89
  • 6
    I don't think this is right. If `a == [[1, -1]]` and `b == [[0, 0]]` won't this pass? – Geoff Oct 19 '18 at 16:31
  • 2
    I should have listened to you, @Geoff… Here's what worked [better for me](https://stackoverflow.com/a/44218701/5734097). @berak, your code works well, but when "b" was "pure white", I got false negative… – D.Kastier Sep 06 '21 at 11:57
7
import cv2
import numpy as np
a = cv2.imread("picture1.png")
b = cv2.imread("picture2.png")
difference = cv2.subtract(a, b)    
result = not np.any(difference)
if result is True:
    print("Pictures are the same")
else:
    print("Pictures are different")
Ishaan Sharma
  • 89
  • 1
  • 2
1

If they are same files except being saved in different file-names, you can check whether their Checksums are identical or not.

herohuyongtao
  • 49,413
  • 29
  • 133
  • 174
0

Importing the packages we’ll need — matplotlib for plotting, NumPy for numerical processing, and cv2 for our OpenCV bindings. Structural Similarity Index method is already implemented for us by scikit-image, so we’ll just use their implementation

# import the necessary packages
from skimage.measure import structural_similarity as ssim
import matplotlib.pyplot as plt
import numpy as np
import cv2

Then define the compare_images function which we’ll use to compare two images using both MSE and SSIM. The mse function takes three arguments: imageA and imageB, which are the two images we are going to compare, and then the title of our figure.

We then compute the MSE and SSIM between the two images. We also simply display the MSE and SSIM associated with the two images we are comparing.

def mse(imageA, imageB):
    # the 'Mean Squared Error' between the two images is the
    # sum of the squared difference between the two images;
    # NOTE: the two images must have the same dimension
    err = np.sum((imageA.astype("float") - imageB.astype("float")) ** 2)
    err /= float(imageA.shape[0] * imageA.shape[1])

    # return the MSE, the lower the error, the more "similar"
    # the two images are
    return err
def compare_images(imageA, imageB, title):
    # compute the mean squared error and structural similarity
    # index for the images
    m = mse(imageA, imageB)
    s = ssim(imageA, imageB)
    # setup the figure
    fig = plt.figure(title)
    plt.suptitle("MSE: %.2f, SSIM: %.2f" % (m, s))
    # show first image
    ax = fig.add_subplot(1, 2, 1)
    plt.imshow(imageA, cmap = plt.cm.gray)
    plt.axis("off")
    # show the second image
    ax = fig.add_subplot(1, 2, 2)
    plt.imshow(imageB, cmap = plt.cm.gray)
    plt.axis("off")
    # show the images
    plt.show()

Load images off disk using OpenCV. We’ll be using original image, contrast adjusted image, and our Photoshopped image

We then convert our images to grayscale

# load the images -- the original, the original + contrast,
# and the original + photoshop
original = cv2.imread("images/jp_gates_original.png")
contrast = cv2.imread("images/jp_gates_contrast.png")
shopped = cv2.imread("images/jp_gates_photoshopped.png")
# convert the images to grayscale
original = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
contrast = cv2.cvtColor(contrast, cv2.COLOR_BGR2GRAY)
shopped = cv2.cvtColor(shopped, cv2.COLOR_BGR2GRAY)

We will generate a matplotlib figure, loop over our images one-by-one, and add them to our plot. Our plot is then displayed to us.

Finally, we can compare our images together using the compare_images function.

# initialize the figure
fig = plt.figure("Images")
images = ("Original", original), ("Contrast", contrast), ("Photoshopped", shopped)
# loop over the images
for (i, (name, image)) in enumerate(images):
    # show the image
    ax = fig.add_subplot(1, 3, i + 1)
    ax.set_title(name)
    plt.imshow(image, cmap = plt.cm.gray)
    plt.axis("off")
# show the figure
plt.show()
# compare the images
compare_images(original, original, "Original vs. Original")
compare_images(original, contrast, "Original vs. Contrast")
compare_images(original, shopped, "Original vs. Photoshopped")

Reference- https://www.pyimagesearch.com/2014/09/15/python-compare-two-images/

Shadab Hussain
  • 794
  • 6
  • 24
0

I have done this task.

Compare file sizes. Compare exif data. Compare first 'n' byte, where 'n' is 128 to 1024 or so. Compare last 'n' bytes. Compare middle 'n' bytes. Compare checksum

Doug Rogers
  • 21
  • 1
  • 3
0

@D.Kastier referenced good solutions for comparing two images (https://stackoverflow.com/a/44218701/5734097) but since you asked for the fastest method, I have to mention hardware acceleration (especially since you are using OpenCV which has e.g.: OpenCL support). To get the benefits of OpenCL on a GPU/NPU you need to use UMat instead of Mat. There are some difference between the two implementations but in many cases they work as a drop-in replacement. And if you don't have a GPU/NPU? No problem, because OpenCV T-API will detect that and instead use your CPU. I haven't tested for the fastest method and it might be necessary to upload while comparing to get good gain out of this. The following code is based on: https://stackoverflow.com/a/64022887/1884837

bool areEqual(const cv::UMat& a, const cv::UMat& b)
{
    cv::UMat temp;
    cv::bitwise_xor(a,b,temp);
    return !(cv::countNonZero(temp.reshape(1)));
}

int main() {
    //Read a Mat using imread and upload it to a GPU/NPU device if there is one.
    UMat image0 = imread("00.png").getUMat(cv::ACCESS_READ);
    UMat image1 = imread("01.png").getUMat(cv::ACCESS_READ);
    return areEqual(image0, image1);
}
kallaballa
  • 337
  • 2
  • 8