Lena (a standard test image in the graphics programming world) is transformed by the Perlin gain function with b = 0.5, b = 0.4, and b = 0.65, respectively (left to right).
Coaxing more contrast out of an image is a kind of exercise in weak-signal detection. You're trying to make information more obvious in the presence of noise. In practice, it comes down to making light tones lighter and dark ones darker. But you have to do it carefully, in such a way as not to force too many (preferably no) dark tones into total blackness nor too many light tones into total whiteness.
The Perlin gain function maps the unit interval (i.e., real numbers from 0 to 1, inclusive) onto itself in such a way that a control value of 0.5 maps [0..1] to [0..1] unchanged, whereas a control-parameter value of (say) 0.25 maps the number 0.5 to itself but maps all other values in the unit interval to new values, as shown in the figures below. (In each graph, the x- and y-axes go from zero to 1.0.)
In the function shown above, the control parameter (the formal parameter that throttles the function) is b. The input value that will be mapped to a different output is a. If b is 0.5, then the output of the function will always be a no matter what value of a you pass in. But if b is 0.25, and a is (say) .4, the function will return 0.456, whereas if b is 0.75 and a is 0.4, the output will be 0.32. In one case, a got bigger, and in the other case it got smaller. The function has the effect of making bigger values bigger and smaller values smaller when b > 0.5. It has the effect of making bigger values smaller and smaller values bigger when b < 0.5.
Gain = 0.25
Gain = 0.5
Gain = 0.75
This turns out to be a great function for changing the contrast of an image. All you have to do is re-map pixel values onto the [0..255] interval using the function, with a value for b of something greater than 0.5 if you want the image to have more contrast, or less than 0.5 if you want the image to have less contrast.
It turns out Java.awt.image has a built-in class called LookupOp that implements a lookup operation from a source color table to an output color, which makes it easy to implement extremely high performance contrast adjustment via the gain function. The red, green, and blue values in an RGB image span the interval zero to 255. All we need to do is create a byte array of length 256, containing those values, then modify the table by passing each value through the gain function. The altered table can be used to create a LookupOp instance, and then you just need to call filter() on the instance, passing it an input image and an output (holder) image.
Projects for the future:
- Add a UI to the program to allow contrast to be adjusted in real time with a slider.
- When contrast is increased in a color image, hot parts of the image appear to get hotter and cold parts appear to get colder. Write a modification of the contrast code that compensates for apparent temperature changes.
- In the code as currently written, inaccuracies due to rounding errors are ignored. Rewrite the routine to transform the image to a 16-bit color space, and use a 32K color lookup table rather than a 256-byte table, for the contrast adjustment; then transform the image back to its original color space afterwards.