ha5dzs / colour_sensor_primary_calculator

It converts the spectral curves of an RGB colour sensor to CIE 1931 chromaticity coordinates
5 stars 2 forks source link

Question about Adafruit RGB sensor #1

Open heinemannj opened 3 years ago

heinemannj commented 3 years ago

I'm very interested how I can practically use your chromaticity coordinates for the TCS 34725 color sensor.

"... Once these chromaticity coordinateas are obtained, the sensor's detected colour can be calculated from the ADC values themselves ..."

Can you please provide a practial example for this calculation.

ha5dzs commented 3 years ago

Hi,

Zoltan here.

I made this example for a workshop some time ago, the explanation here should show how it works.

In a nutshell, once you have the coordinates for the three primary channels, you can use the formula in the explanation to make a simple and cheap chromameter. I did this with my sensor, and found out that I got about 10% accuracy, which is pretty impressive: the sensor itself is $5, and the Minolta chromameter, which can do 3% accuracy is something like $2000.

This is now thankfully getting out of date, because we have the WS2812 LEDs, which have pre-set primaries.

heinemannj commented 3 years ago

Hi Zoltan,

first of all thanks for your response. My vision is to use this sensor for a cheap colorimeter.

I wants to measure colors and color differences in CIE Lab. In general I'm able to transform sensors RGB data into XYZ D50 und finally into CIE Lab. But results compared to ColorChecker standard are very bad.

I've reviewed your project but I was not able to understand how to convert xy values into XYZ/Lab.

  *out_x = ( r_luminance / sum_luminance ) * primary_r_x + ( g_luminance / sum_luminance ) * primary_g_x + ( b_luminance / sum_luminance ) * primary_b_x;
  *out_y = ( r_luminance / sum_luminance ) * primary_r_y + ( g_luminance / sum_luminance ) * primary_g_y + ( b_luminance / sum_luminance ) * primary_b_y;

Note: I'm a dummy on colorimetry but I want's to improve :)

heinemannj commented 3 years ago

After thinking a little bit more in depth:

The sensor is providing: RGB raw data Your calculation provides patched values for: xy

Transform: RGB raw data -> XYZ D65: XYZ convert your xy values plus the Y from above back to X'YZ' D65 and then finally into CIE Lab and to sRGB

Right or is there a more easy and reliable way?

ha5dzs commented 3 years ago

Well, with this sensor, it is a bit more complicated than that at first, and this is what made me write the code. Each colour channel is very far from monochromatic, and their sensitivities are also different. I made the curve digitiser in Matlab, and it generates the spectral response in the csv files. Then, these digitised curves are pushed though the integral with the human perception curves, which generate the human perception (to which you refer to as 'XYZ' if I am correct) equivalent stimulus intensities. And finally, the code uses these values to generate the chromaticity coordinates.

This script generates these primary coordinates for your sensor, which now takes not only the spectral responses, but also the relative sensitivity differences into account. From this point onward you won't need the find_chromaticity_of_primaries script ever again.

And finally, now that you know the primary chromaticity coordinates, you can calculate the 'colour' 'seen' by the sensor, with the calculation you referred as above. Effectively, it's an averaging calculation, and the average point is being pulled in the gamut by the three ADC values.

So it is not as complicated as you wrote, because we do more than half the work beforehand. In the production code (your code, that reads the sensor and outputs the chromaticity coordinates), the RGB values from the sensor can then be converted directly to chromaticity coordinates, without any hassle. You will need floating-point numbers though, so it won't be particularly fast.

Oh, and when you see what colour gamut the sensor actually can measure, you will be disappointed. It is much smaller than sRGB.

I think find_chromaticity_of_primaries will also run on Octave, so you won't have to get Matlab. An example set of digitised curves are also included in .csv files, so you can calculate the primaries yourself.

heinemannj commented 3 years ago

Sorry - I can not follow you completely - I will provide an calculation example. Please point me into the right direction.

ColorChecker 2014 References: http://xritephoto.com/documents/literature/en/ColorData-1p_EN.pdf

- Index 10 (Purple)
- sRGB(94 60 108)
- CIE Lab(30.325 22.976 -21.587)

image

CIE Calculator: http://www.brucelindbloom.com/

image

My TCS34725 raw RGB data:

image

image

Color difference of "8" between CIE Lab reference and my measurement - but my measurement was really quick and dirty ...

Using the same TCS34725 sensor raw data but applying your trick

TCS34725 sensor Primary CIE 1931 xy-coordinates based on your research:

Red: x = 0.582692, y = 0.382919
Green: x = 0.283233, y = 0.525670
Blue: x = 0.144560, y = 0.134175

Your xy values calculation advice:

 *out_x = ( r_luminance / sum_luminance ) * primary_r_x + ( g_luminance / sum_luminance ) * primary_g_x + ( b_luminance / sum_luminance ) * primary_b_x;
 *out_y = ( r_luminance / sum_luminance ) * primary_r_y + ( g_luminance / sum_luminance ) * primary_g_y + ( b_luminance / sum_luminance ) * primary_b_y;

My TCS34725 sensor raw data as above:

R = 87.4286
G = 65.5714
B = 102
Sum = 255

My calculation of xy values:

x = (87.4286/255) * 0.582692 + (65.5714/255) * 0.283233 + (102/255) * 0.144560 = 0.330435
y = (87.4286/255) * 0.382919 + (65.5714/255) * 0.525670 + (102/255) * 0.134175 = 0.320129

My Y value from previous calculation sheet:

Y = 6.8033

My xyY values:

x = 0.330435
y = 0.320129
Y = 6.8033

image

image

Big color difference of "23" between CIE Lab reference and your patching advice of my raw RGB data ...

Do you have any explanations?

ha5dzs commented 3 years ago

Can you tell me how did you obtain this measurement? Specifically, what light source (or monitor) you used, and what were the settings for the sensor?

heinemannj commented 3 years ago

My measurement was quick and dirty:

Turn sensor LED off
Integration Time 700ms
Gain 1x
Clear channel was at every time >65535: ~1000
ColorCheckerChart tiff picture displayed on an DELL LED Display
Sensor in an black box parallel to the display - ~1cm above the surface
No other light than the a small monitor array (1,5 x 1,5 cm) is reaching the sensor
heinemannj commented 3 years ago

After reading the 10. time of Bruce Justin Lindbloom documentation I found the following calculations:

http://www.brucelindbloom.com/Eqn_RGB_XYZ_Matrix.html

image

heinemannj commented 3 years ago

But applying the origional sRGB transformation matrix is much more accurate then the one I've calculated with your primaries ...

ha5dzs commented 3 years ago

Strange. A few things that come into my mind: