I have a picture obtained from a camera in an experiment. It's a .dat file, contains only numbers. I can re-create the image by importing it as data and using the Image[*data*] command.

However, I need to use ImageAdjust[Image[data]] to make something visible. Since I want to perform the same adjustment on several pictures, I need to know exactly which values ImageAdjust chooses for brightness, contrast, etc.

How to find out?

  • 2
    $\begingroup$ According to the documentation ImageAdjust[Image[data]] is equivalent to Image[Rescale[data]]. If you want the same adjustment you'll have to specify it explicitly. $\endgroup$ Commented Aug 25, 2015 at 9:17
  • $\begingroup$ I don't see where it says it is equivalent to Rescale, but it is clearly not true for multi channel images. For color images ImageAdjust works independently on each channel while Rescale applies a single transformation to the whole data array. Oddly ImageAdjust does not provide options to manually specify each channel range, so you cant use it directly even if you know the transform the auto setting used. $\endgroup$
    – george2079
    Commented Aug 25, 2015 at 14:01
  • $\begingroup$ MikeLimaOscars answer wasn't directly what I wanted, but playing around with Rescale definitively got me some steps further! Thanks! $\endgroup$
    – keyx
    Commented Aug 26, 2015 at 9:34
  • $\begingroup$ A duplicate question: (14956). $\endgroup$ Commented Apr 4, 2017 at 8:38

3 Answers 3


Here is a look at the default behavior of ImageAdjust on a color image:

 img = ExampleData[{"TestImage", "Lena"}];
 adj = ImageAdjust@img;
 Column[ Table[
   inout  = 
     Transpose@(Flatten[ImageData@ColorSeparate[#][[channel]], 1] & /@
          {img, adj});
   fit = LinearModelFit[ inout , x , x];
      Show[{Plot[fit[x], {x, 0, 1}, PlotStyle -> Red],
         ImageSize -> 300]
          }] , {channel, 3}]]

enter image description here

What you see is a simple linear transform on each channel. We could have got at those numbers just by looking at the data range for each channel:

   range = Sort[
      Flatten[ImageData@ColorSeparate[img][[channel]], 1]][[{1, -1}]];
     ({range[[1]] # , -#} &@ 1/(Subtract @@ range)) , {channel, 3}]

{{-0.268657, 1.26866}, {-0.0122449, 1.04082}, {-0.0368664, 1.17512}}

From this I suppose the answer to the question should be to first pass through all the images and find the absolute range over all the images for each channel, then use ImageApply to do the scaling.

  • $\begingroup$ Thanks a lot, I think this one is exactly what I searched. $\endgroup$
    – keyx
    Commented Aug 26, 2015 at 9:33

Assuming all your images are the same size and channel depth you can create a per pixel, per channel scale factor base on what ImageAdjust has done and multiply each image by it.

adjustImages[keyImage_, images_] := 
 With[{scaleFactor = Flatten@ImageData@ImageAdjust@keyImage/Flatten@ImageData@keyImage}, 
  Image@ArrayReshape[scaleFactor Flatten@ImageData@#,

And apply so:


You may want to decide what the the result should be if rescaling using the key image pushes values beyond the normal range and saturates.

It may also be worth exploring what it actually is you want to adjust in the images to improve performance on whatever pipeline follows, rather than trusting ImageAdjust to optimise things to your requirements.

  • $\begingroup$ ImageAdjust actually does a linear transform, so properly you need to fit to a scale + offset form. (this will work if keyimage has at least one completely black pixel.. ) $\endgroup$
    – george2079
    Commented Aug 25, 2015 at 17:51

Under the "Properties & Relations" on the Documentation page for ImageAdjust we read:

ImageAdjust[image] is equivalent to ImageAdjust[image,{0,0,1},{min,max},{0,1}] where {min,max} is the channel-wise pixel ranges in image:

ImageAdjust[img] == 
 ImageAdjust[img, {0, 0, 1}, ImageMeasurements[img, {"Min", "Max"}], {0, 1}]

So ImageAdjust[img] works channel-wise and by default simply rescales channel values on the base of MinMax ranges returned by ImageMeasurements.

Note however that due to a bug in ImageAdjust currently we have to unpack the output of ImageMeasurements manually:

img = ExampleData[{"TestImage", "Sailboat"}];
ImageAdjust[img] === 
 ImageAdjust[img, {0, 0, 1}, List @@@ ImageMeasurements[img, {"Min", "Max"}], {0, 1}]

The output of ImageMeasurements is just Transpose of MinMax applied separately to each channel:

Transpose[MinMax /@ ImageData[img, Interleaving -> False]] == 
 ImageMeasurements[img, {"Min", "Max"}]

We can also understand the default behavior of ImageAdjust[img] as applying Rescale separately to each channel:

data = ImageData[img, Interleaving -> False];
res1 = ImageAdjust[Image[data, Interleaving -> False]]; 
res2 = Image[Rescale /@ data, Interleaving -> False];
Max@Abs[ImageData[res1] - ImageData[res2]]

It is worth to note here that ImageAdjust always returns an image with the same ImageType as the original image:

ImageType@ImageAdjust@Image[img, #] & /@ {"Bit", "Byte", "Bit16", "Real32", "Real"}
{"Bit", "Byte", "Bit16", "Real32", "Real"}

This explains significant difference which we get in the cases like the following (caused by rounding off the channel values in the case of the "Byte" image):

img = ExampleData[{"TestImage", "Sailboat"}];
res1 = ImageAdjust[img];
res2 = ImageAdjust[Image[img, "Real"]];
Max@Abs[ImageData[res1] - ImageData[res2]]



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.