问题
Is there any equality predicate function in ImageMagick library? I want to compare two images and find whether they are the exactly same (all colors of the pixels are the same) or have any differences.
I’ve looked around, but it seems not to have a such function. Should I write the function using pixel iterators by myself?
回答1:
ImageMagick provides the compare
function to properly compare images.
Checking the md5
checksum of two images is not the correct approach, since some image formats (e.g. PNG and JPEG with EXIF for example), contain the date and time the file was created (see example 1) below, and some files can be visually identical but represented completely differently internally (see example 2), or have different bit-depths (see example 3).
Example 1
# Create two identical images (100x100 pixels, bright red) but with different file contents
convert -size 100x100 xc:red r1.png
convert -size 100x100 xc:red r2.png
# MD5 checksum them
md5 r?.png
MD5 (r1.png) = 9f6d612615efd88c3fd8521d717e9811
MD5 (r2.png) = 996911bec0e0da75af46a1e78c052998 # Mmmm different
# Ask IM to tell us absolute error between the two (number of differing pixels)
compare -metric AE r1.png r2.png null:
0 # No difference - that's better
Why do these two differ in MD5? Because the date is in them...
identify -verbose r[12].png | grep -i date
date:create: 2015-03-03T14:57:26+00:00
date:modify: 2015-03-03T14:57:26+00:00
date:create: 2015-03-03T14:57:43+00:00
date:modify: 2015-03-03T14:57:43+00:00
Example 2
# Create PNG and identical GIF
convert -size 100x100 xc:red r.png
convert -size 100x100 xc:red r.gif
# Compare with MD5 sums
md5 r.png r.gif
MD5 (r.png) = 692ef06b62a15b799d5dc549b0dd3737
MD5 (r.gif) = 549feea78dc438924fbb3e0ef97dc0b3 # Ooops
# Compare properly
compare -metric AE r.gif r.png null:
0 # Identical
Example 3
# Create 8-bit PNG and 16-bit PNG
convert -size 100x100 xc:red PNG8:8.png
convert -size 100x100 xc:red PNG48:48.png
# MD5 sum them
md5 8.png 48.png
MD5 (8.png) = eb3fc9a06e1632c3b41ebb986b81a816
MD5 (48.png) = 32fdf1c30793a4fed941c91d27084e0a # Ooops
# Let ImageMagick compare them
compare -metric AE 8.png 48.png null:
0
Fuzzy Comparison of Images
As Kurt alludes to, this also leads to the possibility of doing a fuzzy compare of images. We can explore that like this:
# Create a grey image, 100x100 and put some noise in it
convert -size 100x100 xc:gray +noise gaussian noise.png
Now multiply all pixels by 1.01 to make them an imperceptible 1% brighter:
# Make pixels 1% brighter
convert noise.png -evaluate multiply 1.01 brighternoise.png
# ... and compare the statistics of the two images
identify -verbose *noise* | grep -E "^Image|mean"
Image: brighternoise.png
mean: 127.235 (0.498959) <--- The brighter image is, well, brighter
Image: noise.png
mean: 126.175 (0.494805)
And now compare them, a few different ways:
# Pixels may differ by up to 2% before being considered different
compare -fuzz 2% -metric AE noise.png brighternoise.png null:
0 # All pixel values within 2% between the 2 images
# Pixels may only differ by 0.5% before being considered different
compare -fuzz 0.5% -metric AE noise.png brighternoise.png null:
594 # 594 of the 10,000 pixels differ by more than 0.5%
# Calculate Root Mean Square Error (RMSE) to see how much pixels tend to differ
compare -metric RMSE noise.png brighternoise.png null:
278.96 (0.00425666) # On average, the pixels differ by 0.4% - i.e. hardly at all
回答2:
Mark's answer is spot-on. However, he forgot to mention that compare
can also return a 'delta image', which will paint any pixel with differences as red, while identical pixels will be white.
# Create a PNG and a JPEG from the builtin 'wizard:' image:
convert wizard: wizard.png
convert wizard: wizard.jpg
Now compare the two:
compare wizard.png wizard.jpg delta.png
This is the 'delta.png':
Lots of differences between PNG and JPEG! Ok, this is explained by the fact that JPEG is a lossy image format...
As you can see, the 'delta.png' has a pale background. If you do not want this background, but only red/white pixels, modify the compare
command:
compare wizard.png wizard.jpg -compose src delta.png
Also, you may want to ignore such differences which are below a certain threshold. Here the -fuzz N%
parameter comes in handy.
You want blue pixels instead of red? And yellow ones instead of white? Here you go:
compare \
-highlight-color blue \
-lowlight-color yellow \
-fuzz 3% \
wizard.png \
wizard.jpg \
delta2.png
You want a textual description of all pixels which are different with their respective coordinates? Here the special output format *.txt
may be good.
Try this:
compare \
-fuzz 6% \
wizard.png \
wizard.jpg \
-compose src \
delta3.txt
The 'delta3.txt' file will be quite large, because it contains one line per pixel in this format:
# ImageMagick pixel enumeration: 480,640,255,srgba
0,0: (255,255,255,0.8) #FFFFFFCC srgba(255,255,255,0.8)
1,0: (255,255,255,0.8) #FFFFFFCC srgba(255,255,255,0.8)
2,0: (255,255,255,0.8) #FFFFFFCC srgba(255,255,255,0.8)
[....]
77,80: (241,0,30,0.8) #F1001ECC srgba(241,0,30,0.8)
[....]
The first column gives the (row,column)
pair of the respective pixel (counting is zero-based, the topmost, leftmost pixel has the address (0,0)
.
The next three columns return the respective pixel color, in 3 different common notation formats.
BTW, ImageMagick can convert the delta3.txt
file back to a real image without any problem:
convert delta3.txt delta3.png
So to get all the pixels which are different (red) into a text file, you could do this:
compare \
-fuzz 6% \
wizard.png \
wizard.jpg \
-compose src \
txt:- \
| grep -v '#FFFFFFCC'
To count the number of different pixels:
compare \
-fuzz 6% \
wizard.png \
wizard.jpg \
-compose src \
txt:- \
| grep -v '#FFFFFFCC' \
| wc -l
With -fuzz 6%
I have 2269
different pixels. With -fuzz 0%
I get 122474
different pixels. (Total number of pixels in these images was 307200
.)
来源:https://stackoverflow.com/questions/7940935/equality-test-of-images-using-imagemagick