ImageAdjust does an excellent job of auto-leveling an image. Although there doesn't appear to be an explicit way to get the contrast, brightness and gamma values from the function, there's an excellent post showing how you might extract reasonable approximations of them via minimization.

My question is: Is there a principled way to reverse the correction performed by an ImageAdjust? For instance, calling

ImageAdjust[img, {-c, -b, 1/g}]


Does a fair job of reversing the correction. If we use the code from the previous link, we can test it out.

ImageAdjustParameters[image_Image] := Module[{img = image},
evalParams[c_?NumericQ, b_?NumericQ, γ_?NumericQ, im_Image] :=
adj = FindMinimum[evalParams[c, b, γ, img], {{c, 0.1, 0, -1, 1}, {b, 0.1, 0, -1, 1}, {γ, 1.1, 1, 0.1, 3}}][[2]];
];

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


ImageSubtract[img, ImageAdjustInverse @@ ImageAdjustParameters[img]]


However, if you run this over and over in a nested fashion, you find the error from the original simply increases.

ListPlot[Table[
ImageSubtract[
img,
ImageData // Max, {x, 1, 5, 1}]]


So it's not a proper inverse. At first one might suspect this is because the original parameters weren't perfect, but regardless of their accuracy, they're what is being used to do the correction. It seems more likely I don't know how to properly reverse those parameters.

My understanding was that c is a coefficient (multiplicative) and b is an offset (additive) while gamma is an exponent. I thought this would mean negating c and b and inverting g would do the trick. What am I doing wrong here?

I apologize in advance if my formatting of this question is poor. I'll try to correct it once I post it!

Two things:

1. ImageAdjust[image] is not, in general, equivalent to ImageAdjust[image, {c, b, g}]. The reason is that ImageAdjust[image] works by directly rescaling the pixel values for each channel to run from 0 to 1, not by choosing a contrast, brightness and gamma adjustment. From the documentation:

2. ImageAdjust[image, {c, b, g}] is not, in general, reversible. This is because it clips out-of-range values. From the documentation:

originalImage = ImageApply[((c + 2 #)/(2 (1 + b) (1 + c)))^(1/g) &, adjustedImage]

• @user986122 are you sure it's perfect? Note that ImageSubtract is not a good test because it is signed, better to use ImageDifference. – Simon Woods Jul 20 '16 at 22:15