Reputation: 1839
I would like to get the average color in rgb of the mask area of a png image.
the following just outputs the average color of the whole image
convert demo.png -mask demo_mask.png -resize 1x1 txt:-
Upvotes: 1
Views: 981
Reputation: 53164
In ImageMagick, -scale 1x1! will ignore the transparent pixels and give you the average of the opaque pixels. So if you want the average of the masked region, you can put the mask into the alpha channel and then use -scale 1x1! to average it down to one pixel. The mask should be white where you want to get the average and black where it should be transparent and ignore those pixels in the average. So this should do it.
convert image.png mask.png -alpha off -compose copy_opacity -composite -scale 1x1! -alpha off -format "%[pixel:u.p{0,0}]" info:
For example if I make the logo: image transparent where it is white and then get the average, I get
convert logo: -transparent white -scale 1x1! -alpha off -format "%[pixel:u.p{0,0}]" info:
srgb(100,81,99)
You can show that this works, by doing it the long way. Multiply the mask by the image, then get the average of each channel of the product. Then get the average of the mask. Then compute the ratios scaled to the range 0 to 255.
convert logo: -transparent white logot.png
convert logot.png -alpha extract mask.png
declare `convert \( logot.png -alpha off \) mask.png -compose multiply -composite -format "IR=%[fx:mean.r]\nIG=%[fx:mean.g]\nIB=%[fx:mean.b]\n" info:`
echo "IR=$IR; IG=$IG; IB=$IB"
IR=0.0651798; IG=0.0529989; IB=0.0641607
MM=`convert mask.png -format "%[fx:mean]\n" info:`
echo "MM=$MM"
MM=0.165872
convert xc: -format "srgb(%[fx:round(255*$IR/$MM)],%[fx:round(255*$IG/$MM)],%[fx:round(255*$IB/$MM)])\n" info:
srgb(100,81,99)
Result is the same as above.
ASIDE: Note that
convert \( logot.png -alpha off \) mask.png -compose multiply -composite ...
in this case is the same as just
convert logot.png -alpha remove ...
But I show it the long way, if the user has a separate mask and image with no transparency.
Upvotes: 2
Reputation: 5395
You should be able to get very nearly what you want with a command something like this...
convert image.png mask.png -compose copyopacity -composite -resize 1x1! txt:-
To output only the color information you can try something like this...
convert image.png mask.png \
-compose copyopacity -composite -resize 1x1! -format "%[pixel:p]" info:
I haven't tried it, but you may have to "-negate" your mask image depending on which version of IM you're using because there have been changes in the way the alpha channel is handled.
You'll get a very slightly different result if you "-trim" before the "-resize".
If you don't want to output the alpha channel information, you can add "-alpha off" after the "-resize".
Upvotes: 2
Reputation: 24439
Perhaps...
convert demo.png -mask demo_mask.png -trim -fx mean -extent 1x1 txt:- |\
tail -1 | cut -d ' ' -f 4
This would work because -trim
will reduce the masked image down to the MBR of the ROI. Fx operator -fx mean
will convert all pixels into the overall average. And finally the -extent 1x1
will isolate the first pixel in the image. The rest is basic unix utilities.
Another option with better performance...
MEAN=$(convert demo.png -mask demo_mask.png -trim -format '%[fx:mean]' info:-)
convert null: -depth 8 -format "%[pixel:$MEAN]" info:-
Or from the Quantization documentation...
convert demo.png -mask demo_mask.png -trim -scale 1x1\! '%[pixel:s]' info:-
Upvotes: 1