Click here to Skip to main content
15,867,686 members
Articles / Multimedia / GDI+

Linear Contrast Stretch of Grayscale Images

,
Rate me:
Please Sign up or sign in to vote.
4.29/5 (9 votes)
2 Apr 2009CPOL5 min read 96.9K   3.9K   20   17
A program to implement piecewise linear contrast stretching on 8-bit grayscale images (C#).

MainScreen.PNG

Introduction

Image processing operations manipulate the individual pixels of an image to yield another image. Point operations transform every single pixel in the input image into the resulting output pixel, and four of these operations have been described in an earlier article of ours. In this article, we implement a piecewise linear contrast stretch operation, with three linear segments. We focus on grayscale images, with bit depth of 8 bits per pixel, where the minimum and maximum pixel values are 0 and 255, respectively.

Our objective in publishing this article is to demonstrate a single image processing (contrast stretch) operation in an application which is simple and easy to understand. It is our endeavor to include a small number of simple classes (not to include more than ten classes), and not to have any external dependencies; thus making it a self-contained application with a specific purpose.

Piecewise Linear Contrast Stretching

The basic transformation is shown in the figure below. In the figure, the horizontal axis r represents the input pixel value, and the vertical axis s represents the output pixel value. As seen, there are three straight line segments used to transform an input pixel to its resulting output pixel value. Stated otherwise, the transformation from the input pixel value to the output pixel value is via the piecewise linear profile shown in the figure. The parameters specifying the contrast stretch mapping are the four values r2, s2, r3, s3, which determine the position of the intermediate straight line segment. Modifying any of these four values modifies the contrast stretch transformation. The values of r1, s1, r4, s4 are fixed.

contrastStretch.PNG

The enclosed application allows the user to modify these values, and displays the resulting image accordingly.

Software Design and Code

The language used for the development of this application is C#, and the development tool is Visual Studio 2008 Express Edition.

The software functionality required is:

  1. To open an image and display it. Since 8-bit grayscale images may not be easily available, an additional functionality is to convert 24-bit or 32-bit colour images to grayscale. The formula used for this conversion is grayscaleValue = 0.3 * red + 0.59 * green + 0.11 * blue.
  2. Plot the piecewise linear contrast stretch profile.
  3. Provide the user with the facility to modify the parameters of the profile.
  4. Update the image based on the profile, and display the updated image accordingly.
  5. Allow the user to view the LUT values corresponding to the currently displayed profile.
  6. Save the updated image.

To speed up the image updating, a lookup table is used. The number of entries in this lookup table is 256 irrespective of the size of the image.

The software is designed to use reusable graphical controls. Two reusable graphical controls are used here (one of them being developed afresh):

  • ImagePanelControl - to display an 8-bit grayscale image, reused from our earlier article referenced in the Introduction above.
  • ContrastStretchControl - to display the piecewise linear contrast stretch profile. This control is designed to display the linear profile, and allow the user to drag the end points of the intermediate line segment. Small red rectangles at the ends of the intermediate line segment can be moved around the rectangular area (on mouse-down and move) to change the position/orientation of the lines. Double-buffering is used to eliminate any flicker during display of the line segments while the mouse is being moved; for this, all drawing is done on a back buffer, and the contents of this back buffer are ultimately transferred to the main graphics of the control. This in addition to setting the control's DoubleBuffered property to true. Upon release of the mouse button, this control computes the lookup table corresponding to the profile. Computation of the lookup table is perhaps the most important function of this control, and its code is given below. In each of the three straight line segment regions, a different formula is used to determine the mapping. Special care is taken when any denominator value becomes zero.
C#
int r2, r3, r4;
double s2, s3, s4;
byte lookUpTable = new byte[256];

public void ComputeLookUpTable()
{
   int i;
   if ((p4.X - p1.X) != 0)
   {
       double p41x = 255.0 / (p4.X - p1.X);
       double p41y = 255.0 / (p4.Y - p1.Y);
       byte b = 0;

       r2 = Convert.ToInt32((p2.X - p1.X) * p41x);
       r3 = Convert.ToInt32((p3.X - p1.X) * p41x);

       s2 = (p2.Y - p1.Y) * p41y;
       s3 = (p3.Y - p1.Y) * p41y;

       int r32 = r3 - r2;
       int r43 = r4 - r3;
       double s32 = s3 - s2;
       double s43 = s4 - s3;
       double factor1 = 0.0, factor2 = 0.0;
       if (r32 != 0) factor1 = s32 / r32;
       if (r43 != 0) factor2 = s43 / r43;

       for (i = 0; i < 256; ++i)
       {
          if (i <= r2)
          {
              if (r2 == 0)
                  b = Convert.ToByte(s2);
              else
                  b = Convert.ToByte(i * s2 / r2);
          }
          else if ((r2 < i) && (i <= r3))
          {
              if (r32 == 0)
                  b = Convert.ToByte(s3);
              else
                  b = Convert.ToByte(s2 + factor1 * (i - r2));
          }
          else // i > r3
          {
              if (r43 == 0)
                  b = Convert.ToByte(s4);
              else
                  b = Convert.ToByte(s3 + factor2 * (i - r3));
          }

          lookUpTable[i] = b;
     }
}

The main form hooks up the different controls together and integrates them into a single application.

Interesting Effects

It is possible to get some interesting effects with this type of contrast stretching.

For example, with a profile as shown below, it is possible to threshold the image. Thresholding maps a range of input pixel values to 0 (black), and its complementary range to 255 (white), thereby creating a binary image. Changing the r-coordinate of the vertical line changes the value of the threshold.

threshold.PNG

Specifying a profile as shown below has the effect of negating (inverting) the image.

negate.PNG

A special effect is obtained with the profile shown below, where some of the intensities are negated, whereas others are not. This has the effect of having both positive and negative parts within the same image.

posneg.PNG

Specifying the profile shown below causes an entire range of input pixel values to map to a single grayscale value, thus causing the image to appear more "uniform".

gray.PNG

Closure and Further Work

A simple application to perform a piecewise linear contrast stretch operation on an image was described above. This application allows the user to open an image and modify the parameters of the contrast stretch operation, upon which the image is updated accordingly. The user can also view the values of the lookup table currently being applied. It is possible to play around with the contrast stretch parameters to see a variety of effects like thresholding, negating, etc. This application was inspired by the book: Digital Image Processing by Gonzalez and Woods.

Further extensions are possible to include a faster way of updating the image. Instead of using just three line segments, it is possible to program for a user-specified number of line segments. Updating the image during mouse-move, rather than during mouse-up, is a possible extension; however, this would require a near-real-time performance, and significantly faster implementation and image updating.

Acknowledgements

The authors would like to thank Harsha T for useful suggestions on the user interface.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India
Programming computers since about 1987, my first computer language was Fortran 77. Later I learnt C, C++ and C#. Also programmed a little in VB .Net. Worked with Enterprise Java for a short while. I love watching Kannada movies, and listening to Kannada songs. Currently studying and understanding the Bhagavad Geetha and teaching Sanskrit on YouTube.



Written By
Software Developer
India India
Email ID: mahe_swe@rediffmail.com

Comments and Discussions

 
QuestionHow do the four values r2, s2, r3, s3 influence the resulted image? Pin
grrigore11-Dec-17 15:00
professionalgrrigore11-Dec-17 15:00 
AnswerRe: How do the four values r2, s2, r3, s3 influence the resulted image? Pin
Amarnath S12-Dec-17 2:20
professionalAmarnath S12-Dec-17 2:20 
GeneralRe: How do the four values r2, s2, r3, s3 influence the resulted image? Pin
grrigore12-Dec-17 4:36
professionalgrrigore12-Dec-17 4:36 
GeneralRe: How do the four values r2, s2, r3, s3 influence the resulted image? Pin
Amarnath S12-Dec-17 16:50
professionalAmarnath S12-Dec-17 16:50 
Generalquestion about Coefficients. Pin
broken_Wings8-Nov-09 22:05
broken_Wings8-Nov-09 22:05 
GeneralRe: question about Coefficients. Pin
Amarnath S8-Nov-09 22:22
professionalAmarnath S8-Nov-09 22:22 
GeneralRe: question about Coefficients. Pin
broken_Wings8-Nov-09 23:02
broken_Wings8-Nov-09 23:02 
GeneralRe: question about Coefficients. Pin
Amarnath S8-Nov-09 23:04
professionalAmarnath S8-Nov-09 23:04 
GeneralRe: question about Coefficients. Pin
broken_Wings8-Nov-09 23:26
broken_Wings8-Nov-09 23:26 
GeneralRe: question about Coefficients. Pin
Amarnath S8-Nov-09 23:40
professionalAmarnath S8-Nov-09 23:40 
GeneralRe: question about Coefficients. Pin
broken_Wings8-Nov-09 23:52
broken_Wings8-Nov-09 23:52 
GeneralRe: question about Coefficients. Pin
Amarnath S9-Nov-09 0:19
professionalAmarnath S9-Nov-09 0:19 
GeneralRe: question about Coefficients. Pin
broken_Wings9-Nov-09 0:38
broken_Wings9-Nov-09 0:38 
QuestionWhat is the grayscale value in case of 16 Bit images? Pin
amolt12-Sep-09 2:36
amolt12-Sep-09 2:36 
AnswerRe: What is the grayscale value in case of 16 Bit images? Pin
Amarnath S13-Sep-09 19:22
professionalAmarnath S13-Sep-09 19:22 
GeneralYour ContrastStretchControl is fun to use! Pin
andre123452-Apr-09 1:12
andre123452-Apr-09 1:12 
GeneralRe: Your ContrastStretchControl is fun to use! Pin
Amarnath S3-Apr-09 1:07
professionalAmarnath S3-Apr-09 1:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.