Rutwick Gangurde
Rutwick Gangurde

Reputation: 4912

Formula for adjusting brightness/contrast on Canvas?

Just as there is a formula for converting an image to grayscale, is there a formula for increasing the brightness of an image and decreasing it in the same level? I tried adding a value to each of the r, g and b pixels. It does increase the brightness but when I reduce the same value, I don't get my original value back.

var pixels = context.getImageData(...);

//loop over the pixel data and add a value
p[i] = p[i]+100;
p[i+1] = p[i+1]+100;
p[i+2] = p[i+2]+100;

This brightens the image. But when I reduce 100 from every pixel, I don't get my original image back.

I read around the web that there are certain formulas to calculate this properly. Can anyone explain it? And similarly for contrast and gamma?

UPDATE:

Thanks all for the suggestions. I tried this after going through some of the posts below.

For increasing brightness:

var pixels = context.getImageData(...);

//loop over the pixel data and add a value
p[i] = p[i]+100 < 255 ? p[i]+100 : 255;
p[i+1] = p[i+1]+100 < 255 ? p[i+1]+100 : 255;
p[i+2] = p[i+2]+100 < 255 ? p[i+2]+100 : 255;

And for reducing brightness:

var pixels = context.getImageData(...);

//loop over the pixel data and add a value
p[i] = p[i]-100 >= 0 ? p[i]-100 : 0;
p[i+1] = p[i+1]-100 >= 0 ? p[i+1]-100 : 0;
p[i+2] = p[i+2]+100 >= 0 ? p[i+2]-100 : 0;

I can see the increment works fine, but when I decrement it, I still don't get the original image, there's a little difference between the original and brightened image!

What am I doing wrong?

Upvotes: 3

Views: 28572

Answers (2)

AngelCastillo
AngelCastillo

Reputation: 2435

A quick search on google showed:

adjust bitmap image brightness/contrast using c++

Links:

https://web.archive.org/web/20091229041814/http://www.kweii.com/site/color_theory/2007_LV/BrightnessCalculation.pdf

https://web.archive.org/web/20140825114946/http://bobpowell.net/image_contrast.aspx

remeber to look for similar questions before you post one :).

EDIT:

Two more links:

Image Processing Algorithms Part 5: Contrast Adjustment:

http://thecryptmag.com/Online/56/imgproc_5.html

Image Processing Algorithms Part 4: Brightness Adjustment:

http://www.dfstudios.co.uk/articles/image-processing-algorithms-part-4/

EDIT:

You have an error in the second block of code you posted:

var pixels = context.getImageData(...);

//loop over the pixel data and add a value
p[i] = p[i]-100 >= 0 ? p[i]-100 : 0;
p[i+1] = p[i+1]-100 >= 0 ? p[i+1]-100 : 0;
p[i+2] = p[i+2]+100 >= 0 ? p[i+2]-100 : 0; // <- Tha p[i+2]+100 should be a p[i+2]-100 right?

What Johannes Jendersie says is true, your problem is this:

Lest say you have a pixel with this values

R = 100;
G = 210;
B = 20;

And you add 100 to each color, now you have:

R = 200;
G = 255; // It was 310 but you have to clamp it to 255.
B = 120;

Now you subtract those same 100:

R = 100; // same
G = 155; // different!, this have to be 210!!
B = 20;  // same

That's why this operation is not reversible. What you can do is always have a copy of the original image, and each time you change the value, you re apply the brightness correction.

So the way to undo your operation of adding 100 is not subtracting a 100 but setting the brightness correction value to 0. This is how many image editing program works, you have a slider and while you are at the slider window changing the value you can always get your original image if you set it to 0, but once you "apply" the correction, it can't be undone, when you re open the slider window the "0" is now the image previously filtered.

So you either keep a backup of the image and a brightnesCorrection value somewhere, and each time the value change, you re-apply the correction on the image, or you just have to accept the fact that you won't be able to restore the image to its former glory xD (at least not with this kind of brightness correction, not sure if there is a better way).

Hope it helps.

Upvotes: 5

Johannes Jendersie
Johannes Jendersie

Reputation: 1010

Many operations on images are not invertible due to the fact of rounding and clamping of values.

Each of your color channels p[i] is probably of type byte? If so it is only possible to store values between 0 and 255. If you add 100 to for example 223 you would end up at 323, what cannot be saved in the 1 byte. This should result in an overflow to 67 or it is clamped to 255 (the biggest possible number). Subtracting 100 will not recover the 223, but result in 155.

Instead of adding an offset you should try multiply your colors. But that is covered by the answer of AngelCastillo. (There you will have loss of information too, but the results are nicer)


Reaction to the Update:

What I meant was, that clamping values (e.g. your actual implementation) results in a loss of data. Like in the explained example above a value which is too large becomes 255. So subtracting 100 again will set all colors to 155, which were 155 or bigger in the original. The information of brighter colors (>155) is lost.

In other cases (contrast and gamma changes) you will also loss information because rounding sets previous different colors to the same value.

The only way to avoid that is the use of other formats with more information per channel. E.g. >16 bit signed int or floating point. I doubt that your canvas has a option to do that, so you need to hold your own background copy (with a higher value range). Do all transformations on your copy and just show the image clamped on the canvas.

Upvotes: 5

Related Questions