7
$\begingroup$

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] := 
        Total[Map[#.# &, ImageData@ImageAdjust[im] - ImageData@ImageAdjust[im, {c, b, γ}], {2}], 2]; 
    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]];
    Return[Flatten @ {ImageAdjust[img, {c, b, γ} /. adj], Values@adj}]
];

ImageAdjustInverse = {img, c, b, γ} \[Function] ImageAdjust[img, {-c, -b, 1/γ}];

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

sample

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

result

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,
        Nest[ImageAdjustInverse @@ ImageAdjustParameters[#] &, img, x]] // 
       ImageData // Max, {x, 1, 5, 1}]]

error

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!

$\endgroup$
9
$\begingroup$

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:

ImageAdjust[Image[data]] is equivalent to Image[Rescale[data]]

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

ImageAdjust[image,{c,b,γ}] is equivalent to ImageApply[Clip[(b+1)(c+1)#^γ-c/2,{0,1}]&,image]

In the absence of clipping you can invert the transformation with

originalImage = ImageApply[((c + 2 #)/(2 (1 + b) (1 + c)))^(1/g) &, adjustedImage]
| improve this answer | |
$\endgroup$
  • $\begingroup$ Maybe you can help me understand this other result I found through a little playing. If I call ImageAdjust[img, {-c, 1 - b, 1/[Gamma]}] I actually get a perfect inversion on my test image (slightly better than the code you sent which has some clipping). I'm not sure why it works though or if I've made some other mistake... $\endgroup$ – user986122 Jul 20 '16 at 21:48
  • 3
    $\begingroup$ @user986122 are you sure it's perfect? Note that ImageSubtract is not a good test because it is signed, better to use ImageDifference. $\endgroup$ – Simon Woods Jul 20 '16 at 22:15
  • $\begingroup$ I'll switch to ImageDifference and run 100 random images to get a sense for it. I ran it just now and it was perfect 91/100 times. I'm trying to see what caused the others to be imperfect right now, but the interesting part is it's perfect on images that the ImageApply method you linked isn't. I'll post back once it's done running! $\endgroup$ – user986122 Jul 20 '16 at 22:25
  • $\begingroup$ If I use ImageDifference instead of ImageSubtract, it fails miserably (while the function you specified works fine except with clipping). I think this was a case of just being tricked by ImageSubtract! $\endgroup$ – user986122 Jul 20 '16 at 22:33
  • $\begingroup$ Yeah your 1-b is making the image much brighter, so subtraction gives a negative result which gets clipped to zero. $\endgroup$ – Simon Woods Jul 20 '16 at 22:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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