Reputation: 7
I am making an auto white balance calibration application. I have a chromameter and api, so my application can measure CIExyY and CIEXYZ. And my app can set the R,G,B output value of my devices's LED panel.
I set the R,G,B value combination and then measured CIEXYZ three times, then I evaluated the following matrix.
I thought that once I evaluated the matrix, I could calculate CIEXYZ using an R,G,B output value.
But it's not the correct value.
The R,G,B output values are 0~1023. 0 doesn't mean 0 output, 0~1023 is just level.
Upvotes: 0
Views: 115
Reputation: 5334
To create the values for your matrix, you first need to determine the individual xyY or XYZ values of each red, green, blue primary in isolation.
This is intended to add on to Kel Solaar's answer.
XYZ is a "pseudo absolute" space, based on a "standard observer", but it requires the use of imaginary primaries that cannot exist in the real world.
Any real RGB color space is necessarily smaller than XYZ. And any given real RGB color space is going to map differently, depending on the coordinates of each individual R, G, B primary.
You mention using a chromameter, i.e. a colorimeter. A colorimeter is not useful for the task of creating the RGB color space, as you need the spectral data for each independent primary. For that you need a spectrophotometer.
Though I imagine that by "chromameter" you might mean spectrophotometer, and the nuance was lost in translation?
Kel's Colour is a very complete library, and I suspect will do everything you need.
If you want the underlying maths, Bruce Lindbloom's site is a useful reference.
As Kel stated, measure each R G amd B in isolation, and R+G+B together to create the values needed to plug into the Colour functions.
Let's look at the subject of linear output of LED's. This from a CREE data sheet for an RGB LED, where normalized forward current is 10ma for green and blue and 15ma for red, for "white".
From this data sheet, the bottom two charts show that between 0 and 10ma (15ma for red), the current to luminous output is fairly linear... BUT on the top two graphs we see that the voltage to current is very non-linear.
So then the question is, what is driving the LEDs? You mention 0-1023 levels—does that relate to a voltage or to a current? I.e. is it a constant current output such that 512 is half the current of 1023?
And is 1023 equal to 15ma 10ma 10ma for R G B? Then is 512 equal to 7.5ma 5ma 5ma?
Because if 512 is half the voltage of 1023, then 512 will not end up as half the current of 1023, and the whitepoint will likely shift.
To correct, plot the output 0-1023 value to a luminance for each primary in isolation, then find an exponent 𝜸 that creates a close match of that curve, then apply exponent 1/𝜸 to the RGB values before transforming to XYZ. (Note that 𝜸 may need to be different for each of the R,G,B, also, probably normalize 0-1023 to 0.0-1.0).
See also: Does LED brightness change with voltage?
Using RGB primaries, you can only emulate a given illuminant—that is, you could create the sensation of the D65 illuminant, but it will not emit the spectral plot of an "actual" D65 (nothing does, but that's another story).
If you are using this device as a light source, such as for photography, the CRI will be very low, and there will be potential problems with metamerism.
Out of curiosity, what is the intended purpose?
Upvotes: 0
Reputation: 4070
Using colour, given the primaries and whitepoint expressed as CIE XYZ tristimulus, you can compute the normalised primary matrix converting from your LED colourspace to CIE XYZ as follows:
import colour
import numpy as np
XYZ_PRIMARIES = np.array(
[
[2.12500000, 1.00000000, -0.00000000],
[0.38405797, 1.00000000, 0.06521739],
[2.50000000, 1.00000000, 13.16666667],
]
)
XYZ_WHITEPOINT = np.array([0.89458689, 1.00000000, 0.95441595])
NPM = colour.normalised_primary_matrix(
colour.XYZ_to_xy(XYZ_PRIMARIES), colour.XYZ_to_xy(XYZ_WHITEPOINT)
)
print(NPM)
print(np.linalg.inv(NPM))
[[ 4.45169812e-01 2.77134409e-01 1.72282669e-01]
[ 2.09491676e-01 7.21595256e-01 6.89130676e-02]
[ -3.63410128e-17 4.70605593e-02 9.07355391e-01]]
[[ 2.72539405 -1.01800301 -0.4401632 ]
[-0.79516802 1.68973205 0.02264719]
[ 0.04124189 -0.08763902 1.10092938]]
You can also create a new RGB colourspace which will allow you to convert to other known colourspaces:
RGB_COLOURSPACE_LED = colour.RGB_Colourspace(
"LED", colour.XYZ_to_xy(XYZ_PRIMARIES), colour.XYZ_to_xy(XYZ_WHITEPOINT)
)
print(RGB_COLOURSPACE_LED)
print(
colour.matrix_RGB_to_RGB(RGB_COLOURSPACE_LED, colour.models.RGB_COLOURSPACE_BT2020)
)
[[ 7.05392504e-01 2.49107517e-01 4.54999792e-02]
[ 4.04429548e-02 9.47423997e-01 1.21330485e-02]
[ -5.83382089e-04 2.69551875e-02 9.73628195e-01]]
Note that this assumes that the LED behave linearly which is almost certainly not the case!
Upvotes: 1