Comparing Images in Node.js with JIMP
By: Chris Webb
Tags: Programming, Jimp, Image Processing, JavaScript, Nodejs

Comparing Images in Node.js with JIMP

The JIMP npm package provides us with methods to compare image files for the purposes of identifying inadvertent duplication or deliberate plagiarism. In this article I will demonstrate how to use them, and along the way we will find out just how similar two images must be to be considered the same.

JIMP and its Image Comparison Methods

JIMP is the JavaScript Image Manipulation Program, and you can read the full documentation on its npm page.

If you just want to install it for this project then run:

npm install --save jimp

I will be using three methods for comparing images:

hash : this returns a 64 bit perceptual hash of an image. Unlike the cryptographic hashes you might be familiar with, perceptual hashes vary in a way roughly proportional to the differences in input, so the hashes of similar images will also be similar.

: this returns a 64 bit perceptual hash of an image. Unlike the cryptographic hashes you might be familiar with, perceptual hashes vary in a way roughly proportional to the differences in input, so the hashes of similar images will also be similar. distance : the Hamming distance between the hashes of two images, ie. the number of bits which differ.

: the Hamming distance between the hashes of two images, ie. the number of bits which differ. diff : the percentage difference between two images.

The JIMP documentation linked to above recommends using both distance and diff to compare images. If either are less than 0.15 then the images can be considered to be the same. They claim 99% success with 1% false positives.

However, there were a few unanswered questions in my mind about this process:

Does it work if one of the images has been converted to black and white?

Does it work if the images are different sizes?

Does it work if one of the images has been slightly enhanced, for example sharpened?

Does it work with heavy editing, for example if one image is highly pixellized?

So as not to keep you in suspense, I found that it does work well in all these cases. I created four images edited in accordance with the above bullet points and all had the exact same hashes as the unedited original (and therefore the same Hamming distances) although the percentage differences did vary quite a bit. However, as long as at least one measure is less than 0.15 the images are flagged as identical according to the recommended methodology.

In this post I will show the source code used to test these cases, using the images below. There is also a completely different image which I have thrown in just to see what happens.

edinburgh_original.jpg

edinburgh_sharpened.jpg

edinburgh_bw.jpg

edinburgh_pixelized.jpg

edinburgh_small.jpg

london.jpg

The source code consists of a single file called comparingimages.js which you can grab from the Github repository. This is the listing.

The compare function is async as I have used await to open the images. As this is just an experiment I have omitted error handling although of course any production code interacting with the outside world, for example the file system, should handle errors.

After the images have been opened the hash of the original image is output. When called with no argument the hash function returns a base 64 number but you can also specify a base. Here I have also printed the binary or base 2 equivalent.

The rest of the code is repetitive, calculating the hash , distance and diff between the original image and each edited image.

The functions used here are relatively resource-intensive and running this program with even six small photos takes 2–3 seconds. Bear this in mind if you happen to be writing any code to compare large numbers of images.

Now let’s run the code…

node comparingimages.js

…which gives us this:

As I mentioned above the hashes and therefore Hamming distances are identical for the Edinburgh photos, although the percentage differences are increasingly higher. Note that “percent” is misleading; these numbers are actually decimals so, for example, 0.5 = 50%.

Not surprisingly the London photo is very different by all measures.