|Using Histogram Stretching to Improve Image Contrast in a Gray-Scale Image|
|Note: The "Max" value in red is the highest
frequency, which is set dynamically.
In the image and histogram above to the left, 23,043 pixels had a "brightness" value of 49.
In the histogram-stretched image and histogram above to the right, 23,043 pixels had a "brightness" value of 165.
The purpose of.this project is to enhance the contrast of a gray-scale image by using histogram stretching.
Materials and Equipment
Delphi 3 - 7 (to recompile)
GIF support to read files requires Anders Melander's TGIFImage and a "GIF" conditional to be set before compilation.
VGA display with 640-by-480 screen in high/true color display mode
Each pixel in a gray-scale image has a brightness from 0 to 255, where 0 is black and 255 is white. A histogram shows the number of pixels with the various levels of brightness. The "0" value on the left of histogram shows the number of pixels that are black. The "255" value on the right of a histogram shows the number of pixels that are white. The histogram is a probability distribution of the brightness levels.
An image has low contrast when the complete range of possible values is not used. For example, the "board" image shown above only uses values 11 through 97 of the possible 0 to 255 range. Inspection of the histogram shows this lack of contrast.
The program automatically converts any color image of any PixelFormat to a pf24bit PixelFormat -- this avoids working with palettes. Each 24-bit color pixel has 8-bits of red, 8-bits of green and 8-bits of blue. A color image can be converted to a gray scale value by computing the "Y" value for each color pixel:
Y = 0.299R + 0.587G + 0.114B
This "Y" value is the grayscale component in the YIQ color space
used in NTSC television. The weights reflect the eye's brightness sensitivity to the
Other methods could have been used for this color-to-grayscale conversion. Often, for convenience, an "Intensity" value is used: I = (R + G + B) / 3.
Once this "Y" value is computed, this "Y" value is then assigned back to each of the R, G, B components of the color pixel. RGB(i,i,i), where i = 0..255, yields a grayscale.
Working with gray-scale images in high-color or true-color environment allows the use of all values 0..255 without special API calls to establish a 256 gray-scale palette. [By default, Windows reserves 20 of the 256 colors in 256-color display mode and a special API call is needed to "reclaim" 18 of the 20 colors. Two of the colors cannot be redefined, but these colors are "black" and "white" and they are needed for the complete 256-gray-scale palette anyway.]
When you process a gray scale image (like the faces 211.JPG and 319.JPG derived from the "Faces" database) the program displays the number of shades of gray to the right of the Read button:
When you process a color image (such as the Mandrill.BMP in the Mandrill.ZIP file) the program displays the original number of colors and the resulting number of shades of gray to the right of the Read button:
After reading the image file, the histogram frequency distribution is computed, as well as a number of other statistics. When a histogram has a single dominant peak, these statistics are often helpful in describing this peak.
The "range of interest" is computed from the histogram based on a percentage parameter. In the examples shown above, the 1% and 99% values are determined using the histogram. Normally this "range of interest" (OriginalRange) is stretched to the full 0 to 255 range to improve the contrast of the image. The percentage value, in effect, defines how many pixels are forced to be at 0 (black) and 255 (white).
The StretchFactor, which is normally 1.00, is used as follows to compute a histogram ScaleFactor:
StretchedRange := OriginalRange + ROUND( StretchFactor
* (255 - OriginalRange) );
ScaleFactor := StretchedRange / OriginalRange;
The intensity of each pixel is inspected and re-assigned based on this ScaleFactor:
NewIntensity := ROUND( ScaleFactor * (OldIntensity - OriginalRangeLeft) );
Each NewIntensity value is forced to 0 if below 0, and forced to 255 if above 255.
Notes about the HistoStretchGrays program:
The FormCreate includes the assignment, OpenPictureDialog.Filter := GraphicFilter(TGraphic), to make sure all registered graphic file formats (especially, JPG and GIF) can be read using the TOpenPictureDialog.
The polymorphic TPicture was used to load images into a TBitmap in ButtonReadImageClick.
The original and histo-stretched images are displayed in a TImage that is 180 pixels wide by 150 pixels high. The "Stretch Image to Fit" checkbox can be used to force large images to fit into the display space.
A single pass through the bitmap was made to inspect every 24-bit pixel. Whenever the R, G and B color components did not match each other, the RGBTripleToY function was called to convert the color pixel to a gray scale. No conversion was made on an image that already contained only gray-scale values.
The CountColors function uses a (usually) sparse 2D matrix of TBits objects. When a given (R,G) combination occurs, the "B" dimension of 256 bits is allocated. A bit is turned "on" for each (R,G,B) combination. After each pixel in an image has been processed, the number of "on" bits is counted, which gives the number of unique (R,G,B) triples in an image.
Whenever the image or one of the parameters is changed, the UpdateDisplay methods updates the graphics and statistics.
The THistogram class definition aids in "counting" pixels and calculating the histogram statistics and drawing the histogram on the specified canvas. The THistogram definition is in the HistogramLibrary.PAS file.
Also see Charles Hacker's Image Processor program that produces a histogram and percentage of dark to light pixels, of an eight bit gray scale Microsoft Windows bitmap.
Histogram stretching is an effective way of improving the contrast of a gray-scale image.
Histogram stretching a color image by applying the technique shown here to the R, G and B color planes will result in an image with high contrast, but often will introduce undesirable color shifts. For example, a poor contrast image of a yellow tulip with green leaves when histostretched will show the yellow tulip but most likely will have blue leaves!
Histogram, grayscale, histogram stretching, RGB, YIQ, TPicture, BMP, JPG, GIF, pixel, TRGBTripleArray, Scanline, TBitmap, TImage, THistoArray, TRGBHistoArray, THistogram, GetStatistics method, GetHistogram method, GetPercentileLevel method, min, max, range, mode, median, mean, standard deviation, kurtosis, math unit, NaN, Plural function, RGBTripleToY function, CountColors function, TBits
Delphi 3 - 7 Source and EXE: HistogramStretchGrays.ZIP
Updated 27 Jun 2003
since 31 May 1999