normalizing mean intensities (grayscale)

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
user001
Posts: 30
Joined: 2015-11-02T01:21:03-07:00
Authentication code: 1151

normalizing mean intensities (grayscale)

Post by user001 »

I have two 16-bit, grayscale images, img1 and img2 and would like to equalize their intensities such that the mean pixel value of each image is the same. In Matlab, I would do this as follows:

Code: Select all

img1 = im2double(imread('img1.tif'));
img2 = im2double(imread('img2.tif'));
img2_eq = im2uint16( img2 ./ mean2(img2) .* mean2(img1) );
I wanted to implement this in ImageMagick and came up with the following, which seems to work:

Code: Select all

img1_mean=$(convert img1.tif -format "%[mean]" info:)
img2_mean=$(convert img2.tif -format "%[mean]" info:)
ratio=$(echo "x=$img1_mean/$img2_mean; scale=5; x/1" | bc -l)
convert img2.tif -evaluate Multiply $ratio img2_eq.tif
My questions are the following:
1. Is there a need to worry about image type when performing such conversions? Based on the fact that the output (img2_eq.tif) appears fine and is still 16-bit grayscale, it appears that ImageMagick handled integer to floating point to integer conversions transparently.
2. Is there a way to achieve this in one line (assuming that the mean of the reference image is precalculated and supplied as a shell variable)? Something along the lines of the following pseudocode:

Code: Select all

convert img2.tif -evaluate Divide "%[mean]" -evaluate Multiply $img1_mean img2_eq.tif
Many thanks.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: normalizing mean intensities (grayscale)

Post by snibgo »

My page Setting the mean shows four methods: multiplying, adding, raisIng to a power, and negative gain, with pros and cons of each method.

With v7, multiplying in one step, assuming both images are opaque and you want to multiply all channels by the same number:

Code: Select all

magick imgA.png imgB.png -set option:MULT %[fx:v.mean/u.mean] -delete 1 -evaluate Multiply %[MULT] imgA_tweaked.png
If imgB is a constant, so you simply want to set the mean to %NEW_MEAN%:

Code: Select all

magick imgA.png -evaluate Multiply %[%NEW_MEAN%/mean] imgA_tweaked.png
This is using statistics from all the channels of all the pixels, so it will work whatever number of channels each image has.

If the images are not in the same colorspace, the result will be wrong.
snibgo's IM pages: im.snibgo.com
user001
Posts: 30
Joined: 2015-11-02T01:21:03-07:00
Authentication code: 1151

Re: normalizing mean intensities (grayscale)

Post by user001 »

Thanks for your help. One image will be a constant and I will be looping over a set of images, setting their mean equal to that of a reference image, so I think your second example is most germane to what I am trying to do. Could you please tell me how %NEW_MEAN% could be introduced as a shell variable (I am using bash)? I tried replacing %NEW_MEAN% directly with a shell variable but the syntax is not correct

Code: Select all

img1_mean=$(convert img1.tif -format "%[mean]" info:)
magick img2.tif -evaluate Multiply %[$img1_mean/mean] img2_eq.tif
I also tried setting the supplied mean as a variable in IM using `-set` but my syntax is wrong there too:

Code: Select all

magick img2.tif -set option:NEW_MEAN $img1_mean -evaluate Multiply %[NEW_MEAN/mean] img2_eq.tif
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: normalizing mean intensities (grayscale)

Post by snibgo »

Sorry, I forgot the "fx:" in the second example. You also need it in the first. I suggest you use "magick" for both commands. In bash:

Code: Select all

img1_mean=$(magick img1.tif -format "%[fx:mean]" info:)
magick img2.tif -evaluate Multiply %[fx:$img1_mean/mean] img2_eq.tif
snibgo's IM pages: im.snibgo.com
user001
Posts: 30
Joined: 2015-11-02T01:21:03-07:00
Authentication code: 1151

Re: normalizing mean intensities (grayscale)

Post by user001 »

Thanks, that works. I'm apparently still in the habit of using the old IM commands (convert, identify, display, montage, etc.). I noticed that `-format "%[fx:mean]"` gives the mean intensity normalized to 1 (i.e., divided by 65535 for 16-bit or 255 for 8-bit images), whereas `-format "%[mean]"` gives the mean intensity in the native bit depth of the image.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: normalizing mean intensities (grayscale)

Post by snibgo »

The same is true of other statistics, eg %[maxima] might give 65535 but %[fx:maxima] gives 1.0. As a rule, normalizing to 1 is more useful (or sometimes to 100, %[fx:100*maxima]).
snibgo's IM pages: im.snibgo.com
Post Reply