Skip to content

elvis-epx/pictdiff

Repository files navigation

pictdiff

This program implements image comparison by generating a picture for visual inspection. It also prints a rough diff metric number, zero means the images are exactly equal.

For example, given two images:

Original image Original image

The difference image generated by the utility looks like this:

Original image

You can compare the images in inverse order, which generates a similar but differently tinted diff image:

Original image

I just want to use it!

The Node.js version has been published in NPMJS, you can install via npm:

sudo npm install -g pictdiff

Usage:

pictdiff old.png new.png diffmap.png

How to interpret the diff image

The diff "blank" image is white. Colorization of the diff image is proportional: pixels are darker as the differences are more intense.

Differences are also tinted to reflect the color changes. For example, if "img1" is generally more red than "img2", then "diff" will be cyan. On the other hand, if "img2" is more red than "img1", then "diff" will be red-tinted.

Differences in alpha (opacity) have twofold effects. They are added to the total absolute difference, which is rendered as gray in diff image. This guarantees that alpha differences will be clearly revealed, even if the color did not change. And, of course, the number returned by the utility will be non-zero.

On top of that, the color channels are multiplied by alpha, so the color differences are mitigated when both images are quite transparent. In the extreme case, two completely transparent images (alpha=0) will be considered equal, even if one is "red" and another is "blue".

Example: these two images are generally clear, except for a transparent area. Given the white background of this page, it is difficult to see the images, but they are there:

Original image Original image

The map generated by pictdiff reveals the transparency differences clearly:

Original image

In this case the inverse map (diff'ing the two images in inverse order) would be equal because the difference is not colored, so either positive or negative differences create darker areas.

Implementations

There is a Python reference implementation, and implementations in other languages: Rust, Go and Node.js.

How to use the Python flavor:

./pictdiff.py img1.png img2.png diff.png

Apart from the "diff" image, the utility also prints a difference metric:

pictdiff/img $ ../pictdiff.py old.png new.png diff.png
2089964

This is a very rough metric, and the number gets big very fast. It is mostly useful to idenfity images that are exactly equal:

pictdiff/img $  ../pictdiff.py old.png old.png diff.png
0

Rust flavor

The Python flavor is quite slow, especially for big imgaes. If you can install the Rust toolchain, you can run the Rust flavor instead:

cargo run --release img1.png img2.png diff.png

After it runs the first time successfully, you can copy the binary from target/release/pictdiff to /usr/local/bin or another convenient location.

Go flavor

Assuming you have the Go toolchain installed and configured:

go build pictdiff.go
./pictdiff old.png new.png diff.png

Run the executable "pictdiff" created in the folder. The command "go run" also runs it, albeit more slowly.

Node.js flavor

Assuming you have Node.js installed, you can run the Javascript flavor locally from the source:

npm install
node pictdiff.js old.png new.png diffmap.png

You can also install pictdiff from npmjs, as shown at the top of te page.

Motivation

The 'compare' tool from ImageMagick almost does what I want, but it marks any difference as a red pixel. The threshold can be configured, but the generated diff image is an all-or-nothing comparison. I needed a diff image for quick inspection of changes, and the image should show the magnitude of these differences, as well as how color was affected.

Performance

The Python flavor is slow. It was the first one and is the reference implementation. Alternative flavors must generate exactly the same results given the same images.

The following table shows the absolute and relative performance of each flavor handling big images (img/big_a.png and img/big_b.png, 4019x2309). Measurements taken after a couple warm-up runs.

Linux x86-64 with Intel i5-7200, measuring wall clock time:

Flavor Relative speed Wall clock time (ms)
Python 3.6.2 1x 56534
PyPy-3.6 7.2 5x 11638
Go 1.13.4 11x 5218 (*)
Node.js 12.13.1 11x 4966
Rust 1.39.0 27x 2084

(*) Goroutines take advantage of the multiple cores and the wall clock time is less than user time (6128).

Mac Mini Late 2014 with somewhat older toolchain and measuring user time + sys time:

Flavor Relative speed User + sys time (ms)
Python 3.7.2 1x 86789
PyPy-3.6 7.1.1 6x 14107
Go 1.12.6 16x 5525
Node.js 12.5.0 19x 4619
Rust 1.25.0 39x 2200

Bugs

Not tested with 48-bit images. (Python Imaging Library does not open 48-bit TIFFs; Rust image crate does not support 48-bit yet.)

Contact

Elvis Pfützenreuter - epxx@epxx.co - https://epxx.co

About

Compare two pictures of same size, generating a diff image for visual inspection

Resources

Stars

Watchers

Forks

Packages

No packages published