A very simple approach to determining the color of a surface is to use one photodiode or photoresitor and a number (3, for example, like in RGB) of LEDs of different colors to light the surface.
Then, in a time-multiplexing fashion, each of the LEDs is turned on by itself in sequence to light the surface, and the intensity of the reflected light is measured for each of them.
Example: If using three LEDs, one red, one green, and one blue, this will yield three reflection intensity values, one for each color component, which together, after possible normalization, will give a numerical approximation of the surface's color in some kind of RGB space (which depends on the specific wavelength distributions of the LEDs, of course).
(I will use the RGB-three-color example setup in the following for simplicity, but any number from 1 to n of differently colored lightsources can be used; the more different colors are used the more exact the surface's color may be determined.)
The principle is the same as in a camera's chip: The intensities of the red, blue, and green components of the incoming light are measured independently and the combination of the three intensities determines the color. In the camera, there is one photodetector for each of those three basic colors so that all three intensities can be measured at the same time. What makes this complicated is that three different sensors or three different filters are needed.
The proposal therefore works the other way around: Instead of filtering the light after it is reflected from the surface one can also 'filter' the light before it hits the surface; basically, for your perception it doesn't matter if you put on your blue-tinted sunglasses or if you use a blue light source and no sunglasses instead.
The intensitiy of reflected light measured for each color component (or LED) will yield a (normalized) value in the range of [0.0, ..., 1.0], where 0.0 means that no light is reflected and 1.0 means that a maximum amount of light is reflected. Depending on the color of the surface the intensities will be different for the different light colors (wavelengths).
In every case, you will receive three intensity values, each of which determines the intensity of a certain part of the color spectrum. Each complete measurement thus yields a triplet (r,g,b) which determines the color measured. As in computer graphics, the triplet (0,0,0) represents complete darkness, black; (1,1,1) is brightest white, and any combination (r,g,b) where r == g == b represents some shade of grey. All other possible combinations identify a distinctive point in the RGB-space, defining the color measured. (0.5,0,0) is some medium red, for example, and (0.9,0.9,0) is some relatively bright yellow, etc..
Note:
- The photodetector must, of course, be sensitive to all of the (3) used light colors.
- The photodetector may need some time to stabilize after switching LEDs before accurate readings can be obtained; photoresistors, for instance, are usually relatively slow. Tens to hundreds of milliseconds may be needed for acceptable precision, minutes for the most exact values.
- Once the hardware is set up, it can be easily calibrated to the surface colors of interest by simply measuring a sample of each. This way, no effort needs to be made in trying to determine exact wavelength distributions or relative brightness of the LEDs, or the relative sensitivity of the sensor for those wavelengths.
- Normalization of the measured values may be needed before actual use. For example, to compensate for stray light from outside, one more measurement may be taken with all LEDs off and the result will then be subtracted from the values measured when LED lit. Generally, the absolute value measured for each color component is of less significance than the relative difference between them.
Some random pages with 'hands on' on the topic:
http://www.societyofrobots.com/sensors_color.shtml
http://www.instructables.com/id/Color-Detection-Using-RGB-LED/#step1
http://letsmakerobots.com/node/23768