C++SDL色彩与灯光---基础3

326 篇文章 2 订阅
183 篇文章 6 订阅

Light and Color

A D V E R T I S E M E N T

Introduction


This  tutorial is about color, which is no doubt a very important aspect of  computer graphics.

First is explained how light is built up and why we actually see different colors.

Then a some color models are explained: first the RGB color model used by computers, and examples showing how to do color arithmetics in RGB, and then the more intuitive HSL/HSV models are explained.

Then code is given that allows you to convert between color models, for example to allow a user to pick a color using the HSV color model and then convert it to RGB so the computer can use it, or to create rainbow gradients, or to change the color of images.

Light



Before starting about color models, it's important to know how the human eye and brain turn light into color.

Light itself is an electromagnetic wave. Electromagnetic waves are similar to sound waves in that they contain different frequencies, but are electromagnetic and can propagate in vacuum. EM waves are thus a signal that's made out of one or more frequencies, for example the EM waves used by a microwave oven are very high frequency, while radio waves are very low frequency. The eye is only sensitive to a very narrow band of frequencies, namely the frequencies between 429 THz and 750 THz (1 THz = 1 TeraHertz = 10^12 Hz). All other EM waves can't be seen.

Monochromatic light is light made up of one single pure frequency (this is certainly not the general case, most light you see is multichromatic). Monochromatic light looks to the eye as a pure color, and can never be white or magenta. Since it contains only one frequency, the wave of monochromatic light can be represented as a sine:



The height of the sine is the amplitude or how bright the light is. The width of one period (called lambda) is the wavelength of the light, and is inversely related to the frequency: since the light travels at 300000000 m/s, it's wavelength is 300000000/f where f is the frequency. So the visible spectrum of light has wavelengths from around 400 to 700 nm.(1 nm = 10^-9 meter).



This visible spectrum shows all the possible colors that can be made out of monochromatic light. Some light sources, such as lasers and Natrium lights, send out monochromatic light, but in general, light is multichromatic. For example, the sun sends out white light, which is light that contains ALL frequencies! That means the sum of red, yellow, green, blue and violet light looks like white! Physically speaking, it's not white at all, it's the sum of a lot of sine curves, but the human brain makes it look white. Color is thus something psychologically, and not something physical.

Lightwaves are a sum of many different frequencies, or the sum of many sine curves. Each of these sine curves has it's own frequency, and can have it's own amplitude. Aspectrum shows for each frequency the amplitude. For more information about spectra in general, see the beginnings of the chapter about Fourier Transforms.

Here's an example of such a spectrum:



It is the spectrum of a yellow LED I found. The top of the spectrum is the Dominant Frequency, and that is the color our eyes will usually see if light with this spectrum shines on it. If this yellow LED would have been monochromatic, the spectrum would have looked like this instead:



And to the eyes, the color would look the same. So here an interesting fact shows up: light with different spectra, can still look the same to the eye! If the human eyes would be able to distinguish every single spectrum as a different color, we would've been able to see gazillions of different colors, but the human eye works differently and turns a whole spectrum into only 3 signals: the amount of detected red, green and blue, and combinations of those make the colors we can see.

The spectrum of white light is as follows (the height of the curve doesn't really matter):



All frequencies are equally much in the light, only then it looks purely white to the brain. In all other cases, a certain frequency will be dominant and then that frequency will be the color the brain sees.

The spectrum of black light looks like this:



Indeed, there's no light at all, the amplitude of every frequency is zero. Black is the color the brain gives to the absence of light.

The spectrum of magenta, a color that can't be made with monochromatic light, could look like this:



Both blue and red have a high amplitude, and the mix of blue and red frequencies looks like magenta or purple to the brain.

The Eye and Color Perception


This section isn't about how the physical structure of the eye and the lens work, but about how the eye and the brain distinguish different colors.

So light falls on the retina, and on the retina are 2 types of cells with photosensitive chemicals, photoreceptors: rods and cones. The rods only detect whether or not light is present, and are important at night. So rods are sensitive to the whole spectrum at once and can't tell what frequency the light has, and thus can't provide any color information. To detect color, you'd need photoreceptors that are sensitive to only a certain frequency. That's exactly what the cones do:

There are 3 types of cones, those that are sensitive to red, those sensitive to green, and those sensitive to blue. Such a rod isn't sensitive to a single frequency, they overlap a bit, it's just sensitive mostly to a certain frequency.

For example, yellow has a frequency between red and green. This yellow frequency will excite both the red and green cones a bit, and the human brain converts the signal "both red and green cones are excited" to "yellow". Even the blue cones are still a bit excited by yellow light, but neglectable.

If light falls on the eye that has two frequencies: red and green, it'll also excite both the red and green cones, so this light will show up as yellow as well, even though it doesn't contain any yellow frequency at all.

If blue light falls on the retina, the blue cones are excited very strongly, while the green and red ones will give only a neglectable signal. And the brain turns the signal "mainly the blue cone is excited" to "blue".

White light contains all frequencies, so if white light falls on the retina, all 3 types of cones are excited, and the brain turns the signal "green, red and blue cones all excited" into "white".

The above explains how the brain creates different "hues" of colors out of the incoming signal, but it also gives a certain brightness to the light, based on how strong the incoming signal is: if it's very strong, the brain indicates it as a very bright red, white, ..., but if it's very weak, it'll be almost black. And then there's also the "saturation" of the color, this is based on the relative difference in strength each color type gives: if the red signal is very strong, but blue and green are also pretty strong, the color will have a low saturation, it's red-grayish or red-whitish. If however the red signal would be very strong, and the blue and green signal very weak, a very red color shows up.

Since different spectra can look exactly the same for us, and some animals have different types of color receptors, it's possible that two colors that look the same to us, look like two different colors for some animal.

The above process happens on every location of the retina separately, so that a complex 2-dimensional image is formed where each location on the image can have it's own color.

Thanks to the 3 types of cones, there are 8 (2^3) main colors one can distinguish:

  • No cones excited: Black
  • Red cones excited, but not the Blue and Green ones: Red
  • Green cones excited, but not the Blue and Red ones: Green
  • Blue cones excited, but not the Red and Green ones: Blue
  • Red and Green cones excited, but no the Blue ones: Yellow
  • Blue and Green cones excited, but no the Red ones: Cyan
  • Red and Blue cones excited, but no the Green ones: Magenta
  • All three the cone types excited: White
You can of  course distinguish much more colors than these 8 because each receptor type can have different levels of excitement.

Color blindness means one or more of the color types of cones are missing or less sensitive, for example if you miss the red one, you can only see the difference between light that has mainly green and light that has mainly blue. Light with mainly red, will show up as green for such a person, because the green receptors are still more sensitive to red than the blue ones. People who have 2 types of cones missing, and have thus only one type left, see in black and white, because only two main types of signals now exist: "the cone is excited" and "the cone is not excited". Imagine how much more colors a human would be able to see if he had 4 types of color receptors instead of only 3.

One final question remains: violet is on one side of the spectrum, while red is totally on the other side. Violet is much closer to the blue receptors of the eye than the red ones, so you'd think violet light would look like pure blue to the eye. But violet looks a bit more like purple, hinting that it has some red in it, why could that be?



The reason is that violet has such a high frequency, too high for the blue receptor as well, that the signal is very weak for both the blue and the red receptor. Relatively speaking, the red and blue signal will thus be pretty close to each other, and the color will show up more like purple than like blue for the brain!

The RGB Color Model


The RGB color model works exactly like those color receptors of the human eye work: the RGB color model describes a color by using 3 variables, Red, Green and Blue. These variables can be compared to the strength of the signals from the 3 types of color receptors in the nerves. A computer or TV screen works this way too: it has 3 types of cells, Red, Green and Blue, and can make each type brighter or darker independently, exciting the correct receptors of the eye to create the desired color. If you look with a magnifying glass to a white area of your computer screen, you can see that the color white is actually made out of the 3 colors red, green and blue. This means the white emitted by a computer screen is different from white sunlight: while white sunlight contains photons of all frequencies (except a few), the computer screen only has 3 frequencies. The human eye can't see the difference between these two kinds of white.

The RGB color model is the one you'll mostly be dealing with in computer graphics. It's also called the additive color model, because you add 3 color components together to form any color. In 24-bit color, each of the 3 components R, G and B is an 8-bit variable that can be an integer number between 0 and 255. 0 means the color component is off (black), while 255 means it's at it's full intensity. 127 is half intensity. This means color 0,0,0 is the darkest black, color 255,0,0 is the brightest red, color 0,255,0 is the brightest green and color 0,0,255 is the brightest blue. 255,255,255 is the brightest white and 127,127,127 is gray. 32-bit color is the same but with an extra 8-bit alpha channel added that can be used for transparency of textures, ...

The RGB color model isn't very intuitive, so here's a table containing some common RGB values:

Here is a table with common RGB color values:

RGBHex Value
Color
000000000Black
25500FF0000Red
0255000FF00Green
002550000FFBlue
2552550FFFF00Yellow
2550255FF00FFMagenta
025525500FFFFCyan
255128128FF8080Bright Red
12825512880FF80Bright Green
1281282558080FFBright Blue
646464404040Dark Grey
128128128808080Intermediate Grey
192192192C0C0C0Bright Grey
255255255FFFFFF White

This way, you should be able to guess that 128,0,0 is dark red, 255,128,192 is pink and 16,16,16 is very dark gray. The Hex value is the hexadecimal code of the color, used for example in HTML.

The R, G and B values are the ones to fill in as parameters for functions of QuickCG like pset, drawLine, drawCircle to give the color.

In RGB color, the higher the values of R, G and B, the brighter the color will be, and if R=G=B, the color will be a shade of gray.

If you set R=x, G=y, B=z, you can represent RGB color on a cube, where the origin is black and the corner at R=255,G=255,B=255 is white:

 

RGB Arithmetic


By doing calculations on the RGB values of the pixels of an image you can perform various color effects.

Here's a table of the operations you can do with RGB color, screenshots and code will follow in the next sections. These operations are given for the 24-bit color model with 8 bit per channel, so 255 is the maximum value of a color. Colors channels can also be represented as floating point numbers between 0.0 and 1.0, then you have to replace the value "255" by "1.0". C represents the channel together or the total color, while R, G and B represent the Red, Green and Blue channel separately.

OperationFormulaEffect
Negative255-CReturns the opposite color, for example white becomes black, red becomes cyan, ...
DarkenC/p or C-pDivide the color though some constant (larger than 1), or subtract a constant from it, to make it darker.
BrightenC*p or C+pMultiply the color by some constant (larger than 1), or add a constant to it, to make it brighter.
Greyscale(R+G+B)/3Calculate the average of the 3 channels to get a gray color with the same brightness.
Remove ChannelR=0, G=0 and/or B=0By setting one or more channels to 0, you completely remove that color component from the picture.
Swap ChannelsR=G, G=R, ...Swap the values of two color channels to get an image with a completely different color.

We'll try all these formulas on the following BMP image of a flower:


NegativeImage


The following code will load a BMP image of 200*133 pixels, calculate it's negative, and display the result. ColorRGB is the struct containing 3 integers r, g and b, to describe the rgb color.

ColorRGB image[200][133]; 
int main(int argc, char *argv[])    
{ 
    screen(200, 133, 0, "RGB Color"); 
    loadBMP("pics/flower.bmp",image[0], 200, 133); 
     
    ColorRGB color; //the color for the pixels 
     
    for(int x = 0; x < w; x++) 
    for(int y = 0; y < h; y++) 
    { 
        //here the negative color is calculated! 
        color.r = 255 - image[x][y].r; 
        color.g = 255 - image[x][y].g; 
        color.b = 255 - image[x][y].b; 
        pset(x, y, color); 
    }    
     
    redraw(); 
    sleep(); 
    return 0; 
}

image[x][y].r is the red component of pixel x, y of the image, so 255 - image[x][y][0] is the negative of it. This is done for each color channel. Here's the result:



You could as well have typed "color = RGB_White - image[x][y]" instead of the 3 lines of code, because the ColorRGB struct supports a few operators.

Change the Brightness



To change the brightness, divide R, G and B through a number larger than 1 to make it darker, or multiply them with that number to make it brighter. If the color component becomes higher than 255, truncate it to 255.

For example, to make the image double as dark, change the 3 lines of code that made the image negative in the previous example, to:

        color.r = image[x][y].r / 2;
        color.g = image[x][y].g / 2;
        color.b = image[x][y].b / 2;



Or to make it 1.5 times as dark, use:

        color.r = int(image[x][y].r / 1.5);
        color.g = int(image[x][y].g / 1.5);
        color.b = int(image[x][y].b / 1.5);



To make it twice as bright, use:

        color.r = image[x][y].r * 2;
        color.g = image[x][y].g * 2;
        color.b = image[x][y].b * 2;

        if(color.r > 255) color.r = 255;
        if(color.g > 255) color.g = 255;
        if(color.b > 255) color.b = 255;



Instead of dividing or multiplying, you can also add or subtract a number instead, this even gives better results when making it brighter:

        color.r = image[x][y].r + 50;
        color.g = image[x][y].g + 50;
        color.b = image[x][y].b + 50;

        if(color.r > 255) color.r = 255;
        if(color.g > 255) color.g = 255;
        if(color.b > 255) color.b = 255;



Or darker:

        ccolor.r = image[x][y].r - 50;
        color.g = image[x][y].g - 50;
        color.b = image[x][y].b - 50;

        if(color.r < 0) color.r = 0;
        if(color.g < 0) color.g = 0;
        if(color.b < 0) color.b = 0;



Greyscale



One way to grayscale an image is to calculate the average of the 3 color components and use this average as the value for the shade of gray:

        color.r = image[x][y].r - 50;
        color.g = image[x][y].g - 50;
        color.b = image[x][y].b - 50;
        color.r = color.g = color.b = (color.r + color.g + color.b) / 3;



Swapping and Removing Channels


By removing channels, you completely remove a color of the image, for example if you remove the red of the flower you get this:

        color.r = 0; //red component set to zero
        color.g = image[x][y].g;
        color.b = image[x][y].b;



If you remove green instead, you get:



And if you remove blue, you get:



The last image looks quite similar to the original because there wasn't much blue in the image, though white areas now look green or yellow, and everything has become a bit darker.

Swapping two channels can give results with a totally different color, for example if we swap the red and green channel the flower becomes green while the background becomes reddish:

        color.r = image[x][y].g; //the green component of the image
        color.g = image[x][y].r; //the red component of the image
        color.b = image[x][y].b; //the blue component of the image



And if red and blue are swapped instead, the flower becomes of course blue:



To make the flower yellow, set both R and G to the red channel of the image:

        color.r = image[x][y].r; //the red component of the image
        color.g = image[x][y].r; //the red component of the image
        color.b = image[x][y].b; //the blue component of the image

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值