Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
631 views
in Technique[技术] by (71.8m points)

image processing - 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...