最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - how to convert Ikea light bulb color XY ( CIE 1931 colorspace ) to RGB - Stack Overflow

programmeradmin2浏览0评论

Problem

i got a similar problem like this one:

How to convert CIE color space into RGB or HEX color code in PHP

how to convert xy color to sRGB? I can't get the formular working xyY. What should i enter for Y?

Setup of the environment

i got an ikea light bulb which gives me a XY color value in the (CIE 1931 colorspace) I would like to convert it into RGB,(sRGB) or HEX.

The Phosconn app is sending the following xy values when setting the colors by full brighness and saturation.

    RED   [0.735, 0.265]
    GREEN [0.115, 0.826]
    BLUE  [0.157, 0.018]

i figured out that the lamp shows deeper colors when i send following values:

    RED   [1.0, 0.0]
    GREEN [0.0, 1.0]
    BLUE  [0.0, 0.0]

To be more precise here is an illustration what i try to achieve:

  1. Retrieve imformation from the bulb (xy color) via zigbee, convert it with javascript to RGB or HEX for the dashboard's color picker

  2. The other way around does already work. Retrieving information from dashboard's color picker (RGB,brightness,saturation) convert it with JS into XY color, brightness and saturation and send it with zigbee to the bulb.

Current Implementation

It's based on the suggested cie-rgb-color-converter NPM module.

function xyBriToRgb(x, y, bri){
   // bri = bri/254*100
    node.warn("XYBRI: "+x+ " | "+y+" | "+bri)
    function getReversedGammaCorrectedValue(value) {
        return value <= 0.0031308 ? 12.92 * value : (1.0 + 0.055) * Math.pow(value, (1.0 / 2.4)) - 0.055;
    }

    let xy = {
        x: x,
        y: y
    };

    let z = 1.0 - xy.x - xy.y;
    let Y = bri / 255;
    let X = (Y / xy.y) * xy.x;
    let Z = (Y / xy.y) * z;
    let r = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
    let g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
    let b = X * 0.051713 - Y * 0.121364 + Z * 1.011530;

    r = getReversedGammaCorrectedValue(r);
    g = getReversedGammaCorrectedValue(g);
    b = getReversedGammaCorrectedValue(b);

    // Bring all negative ponents to zero
    r = Math.max(r, 0);
    g = Math.max(g, 0);
    b = Math.max(b, 0);

    // If one ponent is greater than 1, weight ponents by that value
    let max = Math.max(r, g, b);
    if (max > 1) {
        r = r / max;
        g = g / max;
        b = b / max;
    }

    return {
        r: Math.floor(r * 255),
        g: Math.floor(g * 255),
        b: Math.floor(b * 255),
    };
}
msg.payload = xyBriToRgb(msg.payload.xy[0], msg.payload.xy[1], msg.payload.bri);
node.warn("RGB: "+ JSON.stringify(msg.payload))
return msg;

Results

let rgb = ColorConverter.xyBriToRgb(0.157 ,0.018, 6);
// return {r: 64, g: 0, b: 255}

Research Material

With the help of the fantastic guys here i found some explanations in this Phillips HUE docs which was leading me to a Review of RGB color spaces

Meanwhile i discovered some bugs inside the phosconn api or its the firmware of the bulb, that the saturation can not be set via api.

I found zigbee2mqtt page which could fix all my problems with a page fitting 100% to the model of the ikea bulb Zigbee2MQTT IKEA LED1624G9

Im trying to setup zigbee2mqtt for this, because i got some problems with phosconn and the api not setting correctly brightness and stuff. Also the brightness is just the luminosity of the bulb and has here nothing to do with the color so i assume it's phosconn specific or bulb specific?

Problem

i got a similar problem like this one:

How to convert CIE color space into RGB or HEX color code in PHP

how to convert xy color to sRGB? I can't get the formular working xyY. What should i enter for Y?

Setup of the environment

i got an ikea light bulb which gives me a XY color value in the (CIE 1931 colorspace) I would like to convert it into RGB,(sRGB) or HEX.

The Phosconn app is sending the following xy values when setting the colors by full brighness and saturation.

    RED   [0.735, 0.265]
    GREEN [0.115, 0.826]
    BLUE  [0.157, 0.018]

i figured out that the lamp shows deeper colors when i send following values:

    RED   [1.0, 0.0]
    GREEN [0.0, 1.0]
    BLUE  [0.0, 0.0]

To be more precise here is an illustration what i try to achieve:

  1. Retrieve imformation from the bulb (xy color) via zigbee, convert it with javascript to RGB or HEX for the dashboard's color picker

  2. The other way around does already work. Retrieving information from dashboard's color picker (RGB,brightness,saturation) convert it with JS into XY color, brightness and saturation and send it with zigbee to the bulb.

Current Implementation

It's based on the suggested cie-rgb-color-converter NPM module.

function xyBriToRgb(x, y, bri){
   // bri = bri/254*100
    node.warn("XYBRI: "+x+ " | "+y+" | "+bri)
    function getReversedGammaCorrectedValue(value) {
        return value <= 0.0031308 ? 12.92 * value : (1.0 + 0.055) * Math.pow(value, (1.0 / 2.4)) - 0.055;
    }

    let xy = {
        x: x,
        y: y
    };

    let z = 1.0 - xy.x - xy.y;
    let Y = bri / 255;
    let X = (Y / xy.y) * xy.x;
    let Z = (Y / xy.y) * z;
    let r = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
    let g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
    let b = X * 0.051713 - Y * 0.121364 + Z * 1.011530;

    r = getReversedGammaCorrectedValue(r);
    g = getReversedGammaCorrectedValue(g);
    b = getReversedGammaCorrectedValue(b);

    // Bring all negative ponents to zero
    r = Math.max(r, 0);
    g = Math.max(g, 0);
    b = Math.max(b, 0);

    // If one ponent is greater than 1, weight ponents by that value
    let max = Math.max(r, g, b);
    if (max > 1) {
        r = r / max;
        g = g / max;
        b = b / max;
    }

    return {
        r: Math.floor(r * 255),
        g: Math.floor(g * 255),
        b: Math.floor(b * 255),
    };
}
msg.payload = xyBriToRgb(msg.payload.xy[0], msg.payload.xy[1], msg.payload.bri);
node.warn("RGB: "+ JSON.stringify(msg.payload))
return msg;

Results

let rgb = ColorConverter.xyBriToRgb(0.157 ,0.018, 6);
// return {r: 64, g: 0, b: 255}

Research Material

With the help of the fantastic guys here i found some explanations in this Phillips HUE docs which was leading me to a Review of RGB color spaces

Meanwhile i discovered some bugs inside the phosconn api or its the firmware of the bulb, that the saturation can not be set via api.

I found zigbee2mqtt page which could fix all my problems with a page fitting 100% to the model of the ikea bulb Zigbee2MQTT IKEA LED1624G9

Im trying to setup zigbee2mqtt for this, because i got some problems with phosconn and the api not setting correctly brightness and stuff. Also the brightness is just the luminosity of the bulb and has here nothing to do with the color so i assume it's phosconn specific or bulb specific?

Share Improve this question edited Jan 9, 2022 at 2:45 Devilsmaul asked Jan 6, 2022 at 19:42 DevilsmaulDevilsmaul 331 silver badge5 bronze badges 5
  • Have you looked at this one: stackoverflow./questions/20283401/… – Terry Commented Jan 6, 2022 at 19:48
  • This is the other way around! i would like to convert XY to RGB – Devilsmaul Commented Jan 6, 2022 at 19:50
  • This suggests that you should also have a brightness value. – Andrew Morton Commented Jan 6, 2022 at 19:53
  • @AndrewMorton i am also able to get a brightness value from 0-254. Im not sure if the hue algorithm will work but i will try it. Thanks – Devilsmaul Commented Jan 6, 2022 at 21:10
  • @AndrewMorton i tested my lamp with the given values inside the Document and they are different from the ones i get when setting the lamp with the phosconn app. So i searched the repo of phosconn and found -> Xyz2Rgb Also interesting that there are 2 methods above Rgb2Xyz and Rgb2xy. I guess the Ikea bulb format is a bit different from CIE1931 which phillips is using. – Devilsmaul Commented Jan 6, 2022 at 21:43
Add a ment  | 

2 Answers 2

Reset to default 6

Short Answer

Okay, so what I am seeing there are the xy coordinates of the 1931 chromaticity diagram? From that we can generate a matrix, and thru the matrixes we can generate RGB or XYZ (and xyY in a simple further transform.)

Longer Answer

Those coordinates are "xy" not to be confused with XYZ (because what would color science be if it wasn't pletely confusing?)

XYZ is a color space, and xyY is a derivative, with the xy being coordinates on the 1931 chromaticity diagram:

The Y, luminance (spectrally weighted light) is missing, but let's solve for all three primaries at 255, and let's assume that's white.

One thing I don't have is the "white point"... when you set the RGB values to 255,255,255 what is the color temperature of the white light? In order to create the matrix I made the assumption of D50, reasonable for lighting like this... but it could be lower or even higher.

The math for the matrixes can be seen at Bruce Lindbloom's site: http://brucelindbloom.

Assuming that 255,255,255 creates a white light close to D50 then the matrix to go from XYZ to RGB is:

MATRIX XYZ TO RGB
X 1.4628522474616900 -0.1840680708796900 -0.2743691849401830 R
Y -0.5217863795540330 1.4472188263102400 0.0677218457168470   =   G
Z 0.0349375228787856 -0.0969021860977637 1.2885320438253000 B

But wait...

Where are you getting these xy values? It seems your controller is sending 255 to each of the lights... so, I'm a little confused as to the application?

Assuming white at a given color temperature when all three are at 255, then the relative Y is 1.0 (0.0 to 1.0 scale, though you can also use a 0 to 100 scale instead).

The next question is ... linearity. On a puter monitor, typically sRGB has an output gamma, a power curve of ^2.2 ... an LED bulb probably does not. Are you trying to match a puter monitor?

Assuming not, and assuming that your controller is also a gamma of 1, then 128,128,128 would be a Y of 0.5

If you want to get the whole XYZ from your RGB, that matrix is here:

For reference the RGB to XYZ and the reference whitepoint

MATRIX RGB TO XYZ
R 0.7160822783599350 0.1009309426243870 0.1471718784550240 X
G 0.2581793248508610 0.7249474661542950 0.0168732089948435   =   Y
B 0.0000000000000000 0.0517819618681639 0.7733554122636590 Z
CALCULATED REF WHITE POINT
WP 0.964185099439346 1.00 0.825137374131823

Matrix Sans Neo

Once the matrix is generated, it's fairly simple to process.

You multiply each number of each row with each row of the input channels, and then sum and that gives you the corresponding output.

so for the output to RGB, you go

   X * 1.46285  + Y * -0.184068 + Z * -0.274369  = R 
   X * 0.258179 + Y * 0.724947  + Z * 0.01687    = G 
   X * 0.0      + Y * 0.05178   + Z * 0.773355   = B

If I understood better what you were attempting to acheive, I might be able to be more helpful.

Recalcualted Matrixes

with the white point you gave:

    FINAL RGB TO XYZ MATRIX         
R   0.6491852651246980  0.1034883891428110  0.1973263457324920  X
G   0.2340599935483600  0.7433166037561910  0.0226234026954449  Y
B   0.0000000000000000  0.0530940431254422  1.0369059568745600  Z

    CALCULATED REF WHITE POINT          
WP  0.950000000000001   1.00    1.090000000000000   

    MATRIX  INVERTED  — XYZ TO RGB          
X   1.6135957276619700  -0.2030358522440090 -0.3026422835182280 R
Y   -0.5088917855729640 1.4114545750797300  0.0660482763436608  G
Z   0.0260574473801223  -0.0722725427335469 0.9610256584609440  B

You can use cie-rgb-color-converter NPM module.

let xy = ColorConverter.rgbToXy(255, 0, 0);
// It returns {x: 0.7350000508904126, y: 0.26499994910958735}

The number of xy is same as question example.

But if you want to convert these numbers back to RGB. You need to Brightness parameter.

let rgb = ColorConverter.xyBriToRgb(0.7350000508904126 ,0.26499994910958735 , Brightness);

If you set Brightness to 0, it is darkest light (no light, no color), and all number of RGB es back as zero, because in zero light human eyes can not see anything.

Following example is nearest numbers:

let rgb = ColorConverter.xyBriToRgb(0.7350000508904126 ,0.26499994910958735, 70);
// return {r: 255, g: 0, b: 16}
    
let rgb = ColorConverter.xyBriToRgb(0.11500021676131911 ,0.8259995753701338, 200);
// return {r: 0, g: 255, b: 0}

let rgb = ColorConverter.xyBriToRgb(0.15700016726803506 ,0.01799963360335173, 6);
// return {r: 64, g: 0, b: 255}

Note: cie-rgb-color-converter has a simple problem, after install go to ColorConverter.js and change these lines:

    let red = parseInt(r * 255) > 255 ? 255: parseInt(r * 255);
    let green = parseInt(g * 255) > 255 ? 255: parseInt(g * 255);
    let blue = parseInt(b * 255) > 255 ? 255: parseInt(b * 255);

    red = Math.abs(red);
    green = Math.abs(green);
    blue = Math.abs(blue);

    return {r: red, g: green, b: blue};

to

// Bring all negative ponents to zero

    r = Math.max(r, 0);
    g = Math.max(g, 0);
    b = Math.max(b, 0);

    // If one ponent is greater than 1, weight ponents by that value

        let max = Math.max(r, g, b);
        if (max > 1) {
            r = r / max;
            g = g / max;
            b = b / max;
        }

        return {
            r: Math.floor(r * 255),
            g: Math.floor(g * 255),
            b: Math.floor(b * 255),
        };

@bokup PR it on GitHub.

发布评论

评论列表(0)

  1. 暂无评论