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

Hi, I would like to ask, where did you get the formula for contrast correction factor?any reference?

Thanks

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

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 🙂

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.

I get Grey color when my contrast value goes negative

Why?

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

I get the same problem.

Hi Felix,

Make sure that you are using a float and not an integer for the ‘factor’ variable. If you still cannot get it working, please feel free to post an example of your code so that I can have a look at it and maybe point you in the right direction.

Kind regards,

Francis

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

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

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

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

Oh my goodness,

That actually solved it! Thank you so much!

– Evan

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

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

thanks in advance!

Oh i got it the values are negatives that is why

thanks !

Great Article. Very articulate and precise for a beginner (like me!). Thanks a ton.

You’re very welcome! I’m glad you found it useful.

hello sir, nice tutorials. can I have the projects for my final term demo? thanks

Hi there,

You can use any of the information presented in these tutorials for your final term demo.

Kind regards,

Francis

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.

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

When I make the contrast value negative , even -1 , the entire image turns grey. Why is that?

I’m not sure. Double check the maths, and check that the variable types you have used make sense (e.g. that you are not using a variable defined as a byte to store a number in the -255 to 255 range).

If you still can’t get it working, you could post an example of the code here so that I can have a look.

Kind regards,

Francis

Alright , It turns out , that using float as the factor value fixes the problem. I had used an integer , as the factor value which might have caused the problem.

Thanks Francis.

Yes, the contrast correction factor needs to be stored as a float. I’m glad you got it sorted.

Kind regards,

Francis

good afternoon

please tell me, can you have information about the article 56 issue kriptmag? the network does not have it anymore, I would like to read more

thanks for the answer

The Crypt Mag website is http://www.thecryptmag.com, but it appears it only links to issues 16-54.

If you are looking for issue 56 it is hosted here.

I’ll have a word with the guys and see if the magazine index can be updated.

Kind regards,

Francis

Thank you, I’ll be very grateful to you.