Contrast Adjustment

Image enhancement techniques are used to improve an image, where "improve" is sometimes defined objectively (e.g., increase the signal-to-noise ratio), and sometimes subjectively (e.g., make certain features easier to see by modifying the colors or intensities). Intensity adjustment is an image enhancement technique that maps an image's intensity values to a new range.

To illustrate, this figure shows a low-contrast image with its histogram. Notice in the histogram of the image how all the values gather in the center of the range. If you remap the data values to fill the entire intensity range [0, 255], you can increase the contrast of the image.

The functions described in this section apply primarily to grayscale images. However, some of these functions can be applied to color images as well. For information about how these functions work with color images, see the reference pages for the individual functions.

Adjust Intensity Values to Specified Range

You can adjust the intensity values in an image using the imadjust function, where you specify the range of intensity values in the output image.

For example, this code increases the contrast in a low-contrast grayscale image by remapping the data values to fill the entire intensity range [0, 255].

I = imread('pout.tif');
J = imadjust(I);
figure, imhist(J,64)

This figure displays the adjusted image and its histogram. Notice the increased contrast in the image, and that the histogram now fills the entire range.

Adjusted Image and Its Histogram

Specify Adjustment Limits as Range

You can optionally specify the range of the input values and the output values using imadjust. You specify these ranges in two vectors that you pass to imadjust as arguments. The first vector specifies the low- and high-intensity values that you want to map. The second vector specifies the scale over which you want to map them.

    Note   Note that you must specify the intensities as values between 0 and 1 regardless of the class of I. If I is uint8, the values you supply are multiplied by 255 to determine the actual values to use; if I is uint16, the values are multiplied by 65535. To learn about an alternative way to set these limits automatically, see Set Image Intensity Adjustment Limits Automatically.

For example, you can decrease the contrast of an image by narrowing the range of the data. In the example below, the man's coat is too dark to reveal any detail. imadjust maps the range [0,51] in the uint8 input image to [128,255] in the output image. This brightens the image considerably, and also widens the dynamic range of the dark portions of the original image, making it much easier to see the details in the coat. Note, however, that because all values above 51 in the original image are mapped to 255 (white) in the adjusted image, the adjusted image appears washed out.

I = imread('cameraman.tif');
J = imadjust(I,[0 0.2],[0.5 1]);
figure, imshow(J)

Image After Remapping and Widening the Dynamic Range

Set Image Intensity Adjustment Limits Automatically

To use imadjust, you must typically perform two steps:

  1. View the histogram of the image to determine the intensity value limits.

  2. Specify these limits as a fraction between 0.0 and 1.0 so that you can pass them to imadjust in the [low_in high_in] vector.

For a more convenient way to specify these limits, use the stretchlim function. (The imadjust function uses stretchlim for its simplest syntax, imadjust(I).)

This function calculates the histogram of the image and determines the adjustment limits automatically. The stretchlim function returns these values as fractions in a vector that you can pass as the [low_in high_in] argument to imadjust; for example:

I = imread('rice.png');
J = imadjust(I,stretchlim(I),[0 1]);

By default, stretchlim uses the intensity values that represent the bottom 1% (0.01) and the top 1% (0.99) of the range as the adjustment limits. By trimming the extremes at both ends of the intensity range, stretchlim makes more room in the adjusted dynamic range for the remaining intensities. But you can specify other range limits as an argument to stretchlim. See the stretchlim reference page for more information.

Gamma Correction

imadjust maps low to bottom, and high to top. By default, the values between low and high are mapped linearly to values between bottom and top. For example, the value halfway between low and high corresponds to the value halfway between bottom and top.

imadjust can accept an additional argument that specifies the gamma correction factor. Depending on the value of gamma, the mapping between values in the input and output images might be nonlinear. For example, the value halfway between low and high might map to a value either greater than or less than the value halfway between bottom and top.

Gamma can be any value between 0 and infinity. If gamma is 1 (the default), the mapping is linear. If gamma is less than 1, the mapping is weighted toward higher (brighter) output values. If gamma is greater than 1, the mapping is weighted toward lower (darker) output values.

The figure below illustrates this relationship. The three transformation curves show how values are mapped when gamma is less than, equal to, and greater than 1. (In each graph, the x-axis represents the intensity values in the input image, and the y-axis represents the intensity values in the output image.)

Plots Showing Three Different Gamma Correction Settings

The example below illustrates gamma correction. Notice that in the call to imadjust, the data ranges of the input and output images are specified as empty matrices. When you specify an empty matrix, imadjust uses the default range of [0,1]. In the example, both ranges are left empty; this means that gamma correction is applied without any other adjustment of the data.

[X,map] = imread('forest.tif');
I = ind2gray(X,map);
J = imadjust(I,[],[],0.5);
figure, imshow(J)

Image Before and After Applying Gamma Correction

Adjust Image Intensity Values Using Histogram Equalization

The process of adjusting intensity values can be done automatically by the histeq function. histeq performs histogram equalization, which involves transforming the intensity values so that the histogram of the output image approximately matches a specified histogram. (By default, histeq tries to match a flat histogram with 64 bins, but you can specify a different histogram instead; see the reference page for histeq.)

This example illustrates using histeq to adjust a grayscale image. The original image has low contrast, with most values in the middle of the intensity range. histeq produces an output image having values evenly distributed throughout the range.

I = imread('pout.tif');
J = histeq(I);
figure, imhist(J,64)

Image After Histogram Equalization with Its Histogram

histeq can return a 1-by-256 vector that shows, for each possible input value, the resulting output value. (The values in this vector are in the range [0,1], regardless of the class of the input image.) You can plot this data to get the transformation curve. For example:

I = imread('pout.tif');
[J,T] = histeq(I);

Notice how this curve reflects the histograms in the previous figure, with the input values mostly between 0.3 and 0.6, while the output values are distributed evenly between 0 and 1.

Adjust Contrast Using Contrast-Limited Adaptive Histogram Equalization (CLAHE)

As an alternative to using histeq, you can perform contrast-limited adaptive histogram equalization (CLAHE) using the adapthisteq function. While histeq works on the entire image, adapthisteq operates on small regions in the image, called tiles. Each tile's contrast is enhanced, so that the histogram of the output region approximately matches a specified histogram. After performing the equalization, adapthisteq combines neighboring tiles using bilinear interpolation to eliminate artificially induced boundaries.

To avoid amplifying any noise that might be present in the image, you can use adapthisteq optional parameters to limit the contrast, especially in homogeneous areas.

To illustrate, this example uses adapthisteq to adjust the contrast in a grayscale image. The original image has low contrast, with most values in the middle of the intensity range. adapthisteq produces an output image having values evenly distributed throughout the range.

I = imread('pout.tif');
J = adapthisteq(I);
figure, imhist(J,64)

Image After CLAHE Equalization with Its Histogram

Enhance Color Separation Using Decorrelation Stretching

Decorrelation stretching enhances the color separation of an image with significant band-to-band correlation. The exaggerated colors improve visual interpretation and make feature discrimination easier. You apply decorrelation stretching with the decorrstretch function. See Adding a Linear Contrast Stretch on how to add an optional linear contrast stretch to the decorrelation stretch.

The number of color bands, NBANDS, in the image is usually three. But you can apply decorrelation stretching regardless of the number of color bands.

The original color values of the image are mapped to a new set of color values with a wider range. The color intensities of each pixel are transformed into the color eigenspace of the NBANDS-by-NBANDS covariance or correlation matrix, stretched to equalize the band variances, then transformed back to the original color bands.

To define the bandwise statistics, you can use the entire original image or, with the subset option, any selected subset of it. See the decorrstretch reference page.

Simple Decorrelation Stretching

You can apply decorrelation and stretching operations on the library of images available in the imdata folder. The library includes a LANDSAT image of the Little Colorado River. In this example, you perform a simple decorrelation stretch on this image:

  1. The image has seven bands, but just read in the three visible colors:

    A = multibandread('littlecoriver.lan', [512, 512, 7], ...
    'uint8=>uint8', 128, 'bil', 'ieee-le', ...
    {'Band','Direct',[3 2 1]});
  2. Then perform the decorrelation stretch:

    B = decorrstretch(A);
  3. Now view the results:

    figure, imshow(B) 

Compare the two images. The original has a strong violet (red-bluish) tint, while the transformed image has a somewhat expanded color range.

Little Colorado River Before (left) and After (right) Decorrelation Stretch

A color band scatterplot of the images shows how the bands are decorrelated and equalized:

rA = A(:,:,1);
gA = A(:,:,2);
bA = A(:,:,3);
figure, plot3(rA(:),gA(:),bA(:),'.')
grid on
xlabel('Red (Band 3)')
ylabel('Green (Band 2)')
zlabel('Blue (Band 1)')

rB = B(:,:,1);
gB = B(:,:,2);
bB = B(:,:,3);
figure, plot3(rB(:),gB(:),bB(:),'.')
grid on
xlabel('Red (Band 3)')
ylabel('Green (Band 2)')
zlabel('Blue (Band 1)')

Color Scatterplot Before (left) and After (right) Decorrelation Stretch

Adding a Linear Contrast Stretch

Now try the same transformation, but with a linear contrast stretch applied after the decorrelation stretch:

C = decorrstretch(A,'Tol',0.01);
figure, imshow(C)

Compare the transformed image to the original.

Little Colorado River After Decorrelation Stretch Followed by Linear Contrast Stretch

Adding the linear contrast stretch enhances the resulting image by further expanding the color range. In this case, the transformed color range is mapped within each band to a normalized interval between 0.01 and 0.99, saturating 2%.

See the stretchlim function reference page for more about Tol. Without the Tol option, decorrstretch applies no linear contrast stretch.

    Note   You can apply a linear contrast stretch as a separate operation after performing a decorrelation stretch, using stretchlim and imadjust. This alternative, however, often gives inferior results for uint8 and uint16 images, because the pixel values must be clamped to [0 255] (or [0 65535]). The Tol option in decorrstretch circumvents this limitation.

Was this topic helpful?