ImageMagick: Divide AE distortion by total pixels in fx output info format

Viewed 41

I am trying to use ImageMagick 7 to detect if a specific channel in an image is largely pure black and pure white (plus a little antialiasing, and there's a chance the image could be pure black). This is to distinguish from another kind of image that shares a naming convention but has photographic-like image data in the r/g/b channels.

(Basically both image types are specular maps from different engines. The one I'm trying to differentiate here is more modern and has the metallic map in the blue channel; the other is much older and just has the specular colour in the RGB channels and the gloss map in the alpha.)

Currently I'm comparing the channel to a clone of itself that has had a 50% threshold applied, using the AE metric to see if it's largely the same apart from a small amount of antialiasing, and a fuzz of 1% to account for occasional aberration from pure black/white. This command works, but of course at the moment it only returns the number of distorted pixels:

magick  ( "file.png" -channel b -separate ) ^
        ( +clone -channel b -separate -threshold 50% ) ^
        -fuzz 1% -metric AE -compare ^
        -format "%[distortion]" info:

Because the input image sizes will vary, I want to divide the distortion by the total number of pixels in the image to get the relative amount of the image that's not pure black/white -- under 10% has seemed good so far in my manual testing -- but I can't get the format syntax right. Everything I've tried -- for example "%[fx:%[distortion]/w*h]" -- has given the magick: undefined variable `[distortion]' @ error/fx.c/FxGetSymbol/1169 error.

What syntax should I use? (And if there's a better way to do what I'm doing, I always appreciate it!)

2 Answers

I believe the following is what you want in Imagemagick. Basically you save the distortion in -set option: argument and then use it in -fx later.

However, +clone gives you just the b channel, so there should be no need for -channel b -separate in your second line.

magick  ( "file.png" -channel b -separate ) ^
        ( +clone -threshold 50% ) ^
        -fuzz 1% -metric AE -compare ^
        -set option:distort "%[distortion]" ^
        -format "%[fx:distort/(w*h)]" info:

Fred (@fmw42) has already provided an excellent method. There is another method for differentiating pure black and white images from greyscale images with a fuller tonal scale which may interest you. Credit to Anthony Thyssen for the technique described here.

If you use -solarize 50% in ImageMagick it inverts all the highlights, so it effectively folds your histogram in half and all the whites become pure black and all the near-whites become near blacks. The command looks like this:

magick INPUT -solarize 50% OUTPUT

So, if I apply that to a couple of input images - the first one pure black and near white, the second a greyscale - and show the corresponding output image on the right you'll see the effect:

enter image description here

enter image description here

If you now inspect the mean and standard deviation of the two solarised images:

magick {a,b}-sol.jpg -format "%f, mean: %[mean], stdev: %[standard-deviation]\n" info:         
a-sol.jpg, mean: 2328.91, stdev: 3175.67
b-sol.jpg, mean: 16319.5, stdev: 9496.04

you can see that the mean and standard deviation of the first (pure black and white) image is low because all the bright whites have folded to near blacks, whereas the mean and standard deviation of the greyscale image are both higher because the tones are more spread out.

Related