Equality test of images using ImageMagick

我的梦境 提交于 2019-12-19 04:14:28

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!