Page 1 of 1

normalizing mean intensities (grayscale)

Posted: 2017-09-04T19:30:45-07:00
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.

Re: normalizing mean intensities (grayscale)

Posted: 2017-09-05T04:24:09-07:00
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.

Re: normalizing mean intensities (grayscale)

Posted: 2017-09-05T09:00:55-07:00
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

Re: normalizing mean intensities (grayscale)

Posted: 2017-09-05T09:12:30-07:00
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

Re: normalizing mean intensities (grayscale)

Posted: 2017-09-05T09:44:41-07:00
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.

Re: normalizing mean intensities (grayscale)

Posted: 2017-09-05T10:04:47-07:00
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]).