将 RGB 颜色转换为 XY

Posted

技术标签:

【中文标题】将 RGB 颜色转换为 XY【英文标题】:convert RGB color to XY 【发布时间】:2019-07-06 22:06:33 【问题描述】:

我使用 RUCKUS API 来更改灯的颜色,我需要将颜色从 RGB 转换为 XY 以调用 API。

我试过这段代码:

1) 从颜色对象中获取 RGB 值并将它们转换为 0 到 1 之间的值

 function rgb_to_cie(red, green, blue)
    
        //Apply a gamma correction to the RGB values, which makes the color more vivid and more the like the color displayed on the screen of your device
        var red     = (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92);
        var green   = (green > 0.04045) ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92);
        var blue    = (blue > 0.04045) ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : (blue / 12.92); 

        //RGB values to XYZ using the Wide RGB D65 conversion formula
        var X       = red * 0.664511 + green * 0.154324 + blue * 0.162028;
        var Y       = red * 0.283881 + green * 0.668433 + blue * 0.047685;
        var Z       = red * 0.000088 + green * 0.072310 + blue * 0.986039;

        //Calculate the xy values from the XYZ values
        var x       = (X / (X + Y + Z)).toFixed(4);
        var y       = (Y / (X + Y + Z)).toFixed(4);

        if (isNaN(x))
            x = 0;
        if (isNaN(y))
            y = 0;   
        return [x, y];
    

但它没有提供适当的解决方案。

所以如果我通过 r:182 g: 255 B: 65 这样我得到 x 作为 22932y 作为 35249 (根据 API 文档。)

我该怎么做?

【问题讨论】:

我假设 doc 会告诉你 X,Y 的范围。我会将值缩放到该范围。实际上 x 和 y 应该小于 1(通常),但 API 可能需要一个整数。但是您要的是 X,Y 还是 x,y?并且请不要称它为 CIE:CIE 是 CIE RGB、CIE XYZ、CIE xyz、CIE xyY、CIELAB、CIE LUV 等。 @GiacomoCatenazzi 它的 X 和 Y.. 对不起 CIE 我会改变的。 啊..我在考虑 xy 归一化(注意,你返回小的 x,y。但我没有注意到你的转换。计算假设红色、绿色和蓝色 en.wikipedia.org/wiki/SRGB#Specification_of_the_transformation 中的注释)您的 RGB(如果您使用的是网页颜色或屏幕值)已经经过伽马校正。您应该执行相反的功能:获取线性 R, G、B 抱歉,我没听懂你想说什么。 【参考方案1】:

我得到了解决方案,如果您正在寻找,我会在此处附上答案,

let red = 100
let green = 100
let blue = 100

let redC =  (red / 255)
let greenC = (green / 255)
let blueC = (blue / 255)
console.log(redC, greenC , blueC)


let redN = (redC > 0.04045) ? Math.pow((redC + 0.055) / (1.0 + 0.055), 2.4): (redC / 12.92)
let greenN = (greenC > 0.04045) ? Math.pow((greenC + 0.055) / (1.0 + 0.055), 2.4) : (greenC / 12.92)
let blueN = (blueC > 0.04045) ? Math.pow((blueC + 0.055) / (1.0 + 0.055), 2.4) : (blueC / 12.92)
console.log(redN, greenN, blueN)

let X = redN * 0.664511 + greenN * 0.154324 + blueN * 0.162028;

let Y = redN * 0.283881 + greenN * 0.668433 + blueN * 0.047685;

let Z = redN * 0.000088 + greenN * 0.072310 + blueN * 0.986039;
console.log(X, Y, Z)

let x = X / (X + Y + Z);

let y = Y / (X + Y + Z);

X = x * 65536 
Y = y * 65536

【讨论】:

【参考方案2】:

有几个错误:

首先:您使用的是正常变换公式,其中红色、绿色和蓝色应在 0.0 到 1.0 的范围内。因此,您可能需要将这些值除以 255。

第二:您正在应用伽玛。要转换为 X、Y、Z,您需要线性值。通常我们有经过伽马校正的 RGB(例如像素值)。所以你矫枉过正。相反,你应该应用 gamma 的倒数,这样你就会得到线性 R,G,B,这样你就可以应用线性变换来得到 X,Y,Z。

第三:您返回 x,y 而不是 X,Y 作为您的问题(和评论)。另一方面,你确定你需要 X,Y 吗? x,y 通常用于“颜色”。我希望有一个 x,y + Y(或一些亮度参数)。

您可能应该缩减这些值。如您所见,范围通常是 0 到 1,或 0 到 100(过去),或 0 到 255、0 到 65535。没有标准:这些只是没有单位的数字。 [与电脑屏幕相反,Phillips Hue 应该知道它的最大亮度是多少,但是.. 这是一个例外]。

【讨论】:

感谢您的回答,我会在 doc 中检查所需的值(您在三种方法中告诉过的值),如果需要更多帮助,我会回复。

以上是关于将 RGB 颜色转换为 XY的主要内容,如果未能解决你的问题,请参考以下文章

如何将“背景颜色”转换为 rgb() 格式?

将RGB颜色转换为HEX颜色

将 RGB 颜色转换为英文颜色名称,如 Python 中的“绿色”

将 RGB 颜色值转换为十进制

如何将 RGB 转换为 HTML 颜色?

将像素转换为颜色