Image Processing Algorithms Part 5: Contrast Adjustment

This article was originally published in issue 56 of The Crypt Mag

Last time we looked at adjusting the brightness of an image. This time we are going to look at adjusting the contrast of an image which is a little bit more complex.

The first step is to calculate a contrast correction factor which is given by the following formula where the value C is the desired level of contrast:

The next step is to perform the actual contrast adjustment itself. The following formula shows the adjustment in contrast being made to the red component of a colour:

Translating the above formulas into pseudo-code would give something like this:

   factor = (259 * (contrast + 255)) / (255 * (259 - contrast))
   colour = GetPixelColour(x, y)
   newRed   = Truncate(factor * (Red(colour)   - 128) + 128)
   newGreen = Truncate(factor * (Green(colour) - 128) + 128)
   newBlue  = Truncate(factor * (Blue(colour)  - 128) + 128)
   PutPixelColour(x, y) = RGB(newRed, newGreen, newBlue)

The procedure Truncate() was previously mentioned in part 2 of this series and just ensures that the new values of red, green and blue are within the valid range of 0 to 255.

The value of contrast will be in the range of -255 to +255. Negative values will decrease the amount of contrast and, conversely, positive values will increase the amount of contrast.

Here we have the ‘Lena’ and ‘Mandrill’ images which have had the contrast adjusted by -128 (decreased) and +128 (increased):

‘Lena’ image with contrast adjusted by -128 (left) and +128 (right)
(click images to enlarge)

‘Mandrill’ image with contrast adjusted by -128 (left) and +128 (right)
(click images to enlarge)

Article copyright © 2008, 2010 Francis G. Loch

12 thoughts on “Image Processing Algorithms Part 5: Contrast Adjustment”

  1. Hi Fatima,

    Because I’m using a range of -255 to 255 here to adjust the contrast I have had to use this correction factor so that it will work with the second formula for the contrast adjustment. All the correction factor does is convert the range I’m using to a range of 0 to 129.5. If you are using a different range, e.g. -100 to 100, then that would obviously require a different correction factor to work properly.

    I’ve had a look back through my notes, but I couldn’t find where I originally got this from. I can’t remember if I had calculated this myself or if I’ve read it in a book or online.

    Kind regards,


  2. Hi, could you please explain, why this works (especially why the mapping to 129.5 is needed)? I see it works, but I don’t understand the logic behind it. Thank you :)

  3. Thanks for your question Tiffany. Yes, I probably didn’t explain that part very well as to why the range is 0 to 129.5. This range is only for the contrast correction factor and does not represent a colour value per se. I’ll explain more about this later.

    To recap the formulas are:

    F = 259(C + 255) / 255(259 – C) for the contrast correction factor. C is the contrast (range = -255 to 255).


    R’ = F(R-128) + 128 for the actual contrast adjustment. R is the red colour component (range = 0 to 255).

    Let’s assume that C is zero (i.e. no change in contrast). Using the first formula we work out that F is 1. Using the second equation we see that R’ is the same as R. I’ll illustrate this with some values:

    R / R’
    0 = 0
    64 = 64
    128 = 128
    196 = 196
    255 = 255

    Let’s now assume that C is -255. F now becomes zero. The R’ values will then become:

    R / R’
    0 = 128
    64 = 128
    128 = 128
    196 = 128
    255 = 128

    As you can see with C turned all the way down to -255 the result is a mid-level grey no matter what the R value is.

    Let’s now assume that C is 255. F becomes 129.5. The R’ values will now become:

    R / R’
    0 = -16448
    64 = -8160
    128 = 128
    196 = 8934
    255 = 16575

    And because the R’ values are outside of the acceptable range these will be truncated so in reality the values are:

    R / R’
    0 = 0
    64 = 0
    128 = 128
    196 = 255
    255 = 255

    Now to explain the reason why the range of the contrast correction factor is 0 to 129.5. Yes it’s true that the range should be 0 to 128, but the value of 259 used in the contrast correction factor formula has been rounded for simplicity. To get a range closer to 0 to 128 you would need to use a value of 259.047619047619 instead. However, as you can see from the R’ values you get at the higher contrast levels they end up being quite extreme and end up being truncated anyway so that fact that the range is 0 to 129.5 instead of 0 to 128 is not very significant.

    I hope that explains things more clearly for you. If you still have any questions then please do not hesitate to get back in touch with me.

    1. Hi Jay,

      That’s correct. Decreasing the contrast of an image (i.e. using negative values) causes the colours to move further away from the maximum and minimum intensity values (e.g. 0 and 255). Reducing the contrast all the way down will cause the image to become a pure grey colour with an intensity at the midpoint (e.g. 128).

      Conversely, increasing the contrast (i.e. using positive values) causes the colour intensities to move closer to the maximum and minimum intensity values. At maximum contrast, all the colours will most likely be either 0 or maximum intensity.

      If you have a read further up, I did touch on some of the maths of this. If you have any further questions then please feel free to ask.

      Kind regards,


  4. I was wondering whether there is a way to soften the contrast. I tried adjusting the constants but to no avail.

    I’ll really appreciate a reply even though your post is so old. It’ll be of great help!

    Thank you very much :)


    1. No problem Evan, I’m always happy to help. (^_^)

      By “soften the contrast” do you mean reduce the amount of contrast? If so, it should just be a case of using negative numbers (e.g. -128) for your contrast to do that. For example:

      contrast = -128
      factor = (259 * (contrast + 255)) / (255 * (259 – contrast))
      colour = GetPixelColour(x, y)
      newRed = Truncate(factor * (Red(colour) – 128) + 128)
      newGreen = Truncate(factor * (Green(colour) – 128) + 128)
      newBlue = Truncate(factor * (Blue(colour) – 128) + 128)
      PutPixelColour(x, y) = RGB(newRed, newGreen, newBlue)

      Remember that the Truncate() function truncates the number to a value in the range of 0 to 255:

      Procedure Truncate(value)
      If value < 0 Then value = 0 If value > 255 Then value = 255
      Return value

      If I have misunderstood, could you give me an example of what you are trying to achieve?

      Kind regards,


      1. Hi Francis,
        Thanks so much for replying so quickly! I think what I was getting at, was say instead of using 128 as the contrast, maybe a lesser number? The change in contrast was a little bit too much for me. I tried using lesser numbers like 30, 40, or 90 but the contrast was either too strong, or none at all.
        Does this help?
        Thank you very nuch!
        – Evan

        1. Hi Evan,

          Yes, I understand now.

          You should be able to see a subtle change in contrast going from, say, 128 to 127. The only thing I can think of is that you have the ‘factor’ variable set up for integer numbers instead of floating point numbers. If the variable is an integer it will only store numbers like 0 and 1 so you will get no change or quite a dramatic change. If the variable is a floating point number you will get numbers like 0.1 and 0.5 which should give you subtler changes.

          Kind regards,


          1. Hi Evan,

            Glad you got it sorted.

            I’ll update the article to clarify that the factor variable should be a float and not an integer to avoid further confusion.

            Kind regards,


Leave a Reply

Homepage of Francis G. Loch's various projects

%d bloggers like this: