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:

In order for the algorithm to function correctly the value for the contrast correction factor (F) needs to be stored as a floating point number and not as an integer. The value C in the formula denotes 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, 2015 Francis G. Loch

20 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,

    Francis

  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).

    and

    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,

      Francis

  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 :)

    -Evan

    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
      EndProcedure

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

      Kind regards,

      Francis

      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,

          Francis

          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,

            Francis

  5. Why does my image turns yellow when the contrast is increased especially the black section of the image

    thanks in advance!

  6. Awesome tutorial Francis! Very useful! I was wondering if I need to make an image 2x more contrast, what should be the level C I’m setting? Since this is not a percentage… I’m not sure what C increases the contrast 1x and 2x.

    1. I’m glad you found it useful! (^_^)

      As for giving an image 2x more contrast, I’m not sure if there is an easy way of doing this. If I understand correctly what you are trying to achieve, it would involve you determining how much contrast is already present in the image and then working out what value of C would give you double that amount of contrast (which will vary between different images).

      As I understand the method for measuring the amount of contrast in an image you need to do something like the following:

      1. Work out the average pixel brightness of the image (i.e. add up the brightness of all the pixels in the image and then divide by the number of pixels).
      2. Work out the difference between the brightness of each pixel and the average brightness.
      3. Square the results of each pixel and add them together.
      4. Divide by the total number of pixels.

      If you have an image that is just made up of the one colour (e.g. pure black or white) then your contrast value should be 0.

      I have never tried doing something like this myself, but it should hopefully give you somewhere to start.

      Kind regards,

      Francis

Leave a Reply

Homepage of Francis G. Loch's various projects

%d bloggers like this: