如何将宜家灯泡颜色 XY(CIE 1931 色彩空间)转换为 RGB

how to convert Ikea light bulb color XY ( CIE 1931 colorspace ) to RGB

问题

我遇到了类似的问题:

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

如何将xy颜色转换为sRGB? 我无法让公式工作 xyY。我应该为 Y 输入什么?

环境设置

我有一个宜家灯泡,它在(CIE 1931 色彩空间)中给我一个 XY 颜色值 我想把它转换成 RGB,(sRGB) 或 HEX。

当通过全亮度和饱和度设置颜色时,Phosconn 应用程序正在发送以下 xy 值。

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

我发现当我发送以下值时 lamp 显示更深的颜色:

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

更准确地说,这是我试图实现的一个例子:

  1. 通过 zigbee 从灯泡(xy 颜色)检索信息,使用 javascript 将其转换为仪表板颜色选择器的 RGB 或 HEX

  2. 反之亦然。从仪表板的颜色选择器(RGB、亮度、饱和度)中检索信息,使用 JS 将其转换为 XY 颜色、亮度和饱和度,并使用 zigbee 将其发送到灯泡。

当前实施

它基于建议的 cie-rgb-color-converter NPM 模块。

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 components to zero
    r = Math.max(r, 0);
    g = Math.max(g, 0);
    b = Math.max(b, 0);

    // If one component is greater than 1, weight components 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;

结果

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

研究Material

在这些优秀的人的帮助下,我找到了一些解释 Phillips HUE docs 这导致我 Review of RGB color spaces

与此同时,我在 phosconn api 或其灯泡固件中发现了一些错误,无法通过 api 设置饱和度。

我找到了 zigbee2mqtt 页面,它可以解决我所有的问题,页面 100% 适合宜家灯泡的型号 Zigbee2MQTT IKEA LED1624G9

我正在尝试为此设置 zigbee2mqtt,因为我在使用 phosconn 时遇到了一些问题,api 没有正确设置亮度和其他东西。 此外,亮度只是灯泡的亮度,与颜色无关,所以我假设它是特定于 phosconn 还是特定于灯泡?

您可以使用 cie-rgb-color-converter NPM 模块。

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

xy个数与题例相同

但是如果你想将这些数字转换回 RGB。您需要 Brightness 参数。

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

如果你设置Brightness为0,它是最暗的光(没有光,没有颜色),RGB的所有数字返回为零,因为在零光下人眼什么都看不见。

以下示例是最接近的数字:

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}

注意: cie-rgb-color-converter 有一个简单的问题,安装后转到 ColorConverter.js 并更改这些行:

    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};

// Bring all negative components to zero

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

    // If one component is greater than 1, weight components 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 在 GitHub.

上发布它

简答

好的,所以我看到的是 1931 色度图的 xy 坐标?从中我们可以生成一个矩阵,通过矩阵我们可以生成 RGB 或 XYZ(和 xyY 在一个简单的进一步转换中。)

更长的答案

这些坐标是“xy”,不要与 XYZ 混淆(因为如果颜色科学会是什么这不是完全令人困惑吗?)

XYZ为颜色space,xyY为导数,xy为1931色度图坐标:

缺少 Y、亮度(光谱加权光),但让我们在 255 处求解所有三个原色,并假设它是白色。

我没有的一件事是“白点”...当您将 RGB 值设置为 255,255,255 时,白光的色温是多少?为了创建矩阵,我做了 D50 的假设,对于这样的照明来说是合理的......但它可能更低甚至更高。

矩阵的数学可以在 Bruce Lindbloom 的网站上看到:http://brucelindbloom.com

假设 255,255,255 产生接近 D50 的白光,那么从 XYZ 到 RGB 的矩阵是:

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

但是等等...

您从哪里获得这些 xy 值?您的控制器似乎正在向每盏灯发送 255...所以,我对应用程序有点困惑?

假设在给定色温下所有三个都为 255 时为白色,则相对 Y 为 1.0(0.0 到 1.0 范围,但您也可以使用 0 到 100 范围)。

下一个问题是……线性度。在计算机显示器上,通常 sRGB 具有输出伽玛,功率曲线为 ^2.2 ... LED 灯泡可能没有。您是否正在尝试匹配电脑显示器?

假设不是,并且假设您的控制器也是 1 的伽马,那么 128,128,128 将是 0.5 的 Y

如果您想从 RGB 中获取整个 XYZ,矩阵就在这里:

用于参考 RGB 到 XYZ 和参考白点

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

矩阵生成后,处理起来相当简单。

将每一行的每个数字与输入通道的每一行相乘,然后求和,得到相应的输出。

所以对于输出到 RGB,你去

   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

如果我能更好地理解您想要实现的目标,我可能会提供更多帮助。

重新计算的矩阵

用你给的白点:

    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