# How to retrieve the parameters calculated and used by ImageAdjust?

When ImageAdjust is called with an image, i.e. with one parameter, it returns an automatically adjusted Image. I would like to retrieve the {contrast, brightness, gamma} values ImageAdjust has calculated and use them as starting points for a following interactive manipulation of these value using ImageAdjust[img, {contrast, brightness, gamma}], i.e. with four parameters.

An obvious solution is to perform an image histogram equalization and calculate {contrast, brightness, gamma}. However, since Mathematica provides the solution somewhere in its code and I intend to continue using ImageAdjust I would rather conform with the already implemented algorithm.

Hence, my questions is: How do I retrieve the parameters calculated and used by ImageAdjust when it runs automatically?

-

Major update at the bottom. First part may be obsolescent.

A brute force approach:

Define a function that provides a measure of the difference between the automatically adjusted image and an image with given contrast, brightness and gamma adjustments (for now, this only works for images that are made of a raster of color triplets):

ClearAll[f];
f[c_?NumericQ, b_?NumericQ, γ_?NumericQ, im_Image] :=


Get an image:

img=Import["http://i.stack.imgur.com/nAaCm.png"]


Now minimize the image differences:

adj = FindMinimum[f[c, b, γ, img], {{c, 0.1, 0, -1, 1}, {b, 0.1, 0, -1, 1}, {γ, 1.1, 1, 0.1, 3}}]


{14.19915417, {c -> -0.06143890985, b -> 0.09520280553, γ -> 1.094933574}}

Comparison of original image and automatically adjusted image:

Row[{img, ImageReflect[ImageAdjust[img], Left -> Right], img}]


Row[{ImageAdjust[img, {c, b, γ} /. adj[[2]]],
]


The differences are small:

ImageSubtract[ImageAdjust[img, {c, b, γ} /. adj[[2]]], ImageAdjust[img]]


And 'small' is this:

ImageSubtract[ImageAdjust[img, {c, b, γ} /. adj[[2]]], ImageAdjust[img]] // ImageData // Max


0.0431372549

Using ImageAdjust itself to enhance those differences:

ImageSubtract[ImageAdjust[img, {c, b, γ} /. adj[[2]]], ImageAdjust[img]] // ImageAdjust


Not quite an exact match but close.

EDIT

Originally, I believed that ImageAdjust does a simple histogram stretch, scaling the maximum pixel value to 1 and the minimum to 0, basically this:

imgd = img // ImageData;
min = Min[imgd];
max = Max[imgd];
Rescale[imgd, {min, max}, {0, 1}]


But that simply didn't work out. If I use the measure introduced in the beginning to determine the difference between the {c,b,γ}-adjusted pictures and the automatically ImageAdjusted pictures on the one hand and the rescaled pictures and the automatically ImageAdjusted pictures on the other hand, the {c,b,γ} seems to be better 4 out of the 5 test images I used it on.

(
img = #;
imgd = img // ImageData;
min = Min[imgd];
max = Max[imgd];
adj = FindMinimum[f[c, b, γ, img],
{{c, 0.1, 0, -1, 1}, {b, 0.1, 0, -1, 1}, {γ, 1.1, 1, 0.1, 3}}];
{Total[Map[#.# &,
2],
Total[Map[#.# &, ImageData@ImageAdjust[img]-Rescale[imgd, {min, max}, {0, 1}], {2}], 2]
}
) & /@ { ...images...}


For the five pictures on the ImageAdjust doc page I get:

{{50.5394233, 81.76899059}, {14.19915417, 14.46839005}, {30.34660515, 46.0902785}, {6.459238754, 2.528418174}, {537.6580546, 1011.243348}}

It seems that ImageAdjust does more than a simple stretching of the values. It probably uses histogram equalization, which linearizes the cumulative distribution function of the pixel intensity values. This is a rather non-linear transformation. It probably requires a transformation to another color space first, to separate color values from luminance values (CIELab for instance). The transformation will then be done on the luminance component only after which an inverse color space transformation occurs.

Yet another edit

Trying to test the hypothesis Mathematica is using histogram equalization.

Load an image and turn it into grayscale (we won't do this colorspace hence and forth stuff here):

img = Import["http://i.stack.imgur.com/xGMge.png"]
imgG = ImageData[ColorConvert[img, "Grayscale"]];


Do histogram equalization:

ClearAll[cdf];
SetAttributes[cdf, Listable]
Scan[(cdf[#[[1]]] = #[[2]]) &,
Transpose[MapAt[Accumulate, Transpose[Sort@Tally[Flatten[imgG]]], 2]]]
imgH = (cdf[imgG] - cdf[Min[imgG]])/(Times @@ ImageDimensions[img] - cdf[Min[imgG]]);


Accumulated counts before equalization:

ListPlot@Transpose[MapAt[Accumulate, Transpose[Sort@Tally[Flatten[imgG]]], 2]]


Accumulated counts after equalization:

ListPlot@Transpose[MapAt[Accumulate, Transpose[Sort@Tally[Flatten[imgH]]], 2]]


Image comparisons:

Original grayscale image:

imgG // Image


imgG // Image // ImageAdjust


Histogram equalized image:

imgH // Image


Clearly, ImageAdjust does not do a histogram equalization.

Final edit

For grayscale images at least, Mathematica seems to do a simple rescaling after all. The rescaling I used above used the minimum and maximum values measured over all color channels. In a grayscale image, rescaling with

Rescale[imgG, {Min[imgG], Max[imgG]}, {0, 1}]


yields an image that is virtually identical to the adjusted image:

(imgG // Image // ImageAdjust // ImageData) -
Rescale[imgG, {Min[imgG], Max[imgG]}, {0, 1}] // Abs // Max


2.220446049*10^-16

So, conclusion: there are no {c, b, γ} parameters to be estimated because ImageAdjust, called without additional parameters, doesn't use them.

-
+1 Cool question & solution ;) Nice to see clean convergence in 3-parameters space. – Vitaliy Kaurov Nov 20 '12 at 23:16
Here, one could use FindArgMin[] instead of FindMinimum[], since we're only interested in the parameters (as opposed to the minimum value.) – J. M. Nov 21 '12 at 0:07
Thank you very much. That is neat, is very well presented and works well. But a) it is not really what I asked for and b) it is fairly slow. The actual issue is, the values have already been calculated by ImageAdjust and I wonder if there isn't a simple way to get them with the adjusted image. – Ernst Stelzer Nov 21 '12 at 8:45
@ErnstStelzer Please see my final edit: there seem to be no parameters to be estimated after all. – Sjoerd C. de Vries Nov 21 '12 at 10:44
@ErnstStelzer Sjoerd conclusions is with agreement with the fact Matthias stated in his answer. Indeed, no parameters to estimate. – Vitaliy Kaurov Nov 21 '12 at 13:04

With only one argument, ImageAdjust[img] performs histogram stretching, ie. pixel values, which run from min to max in img, are rescaled so they run from 0 to 1 in the ouput image.

The setting {contrast, brightness, gamma} = {0, 0, 1} does not change anything: ImageAdjust[img, {0, 0, 1}] === img gives True.

-