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:
The difference image generated by the utility looks like this:
You can compare the images in inverse order, which generates a similar but differently tinted diff image:
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
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:
The map generated by pictdiff reveals the transparency differences clearly:
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.
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
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.
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.
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.
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.
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 |
Not tested with 48-bit images. (Python Imaging Library does not open 48-bit TIFFs; Rust image crate does not support 48-bit yet.)
Elvis Pfützenreuter - [email protected] - https://epxx.co