生成等亮度的纯色(用于 LED 显示)
Generating pure colors of equal brightness (for display on LEDs)
我有一些 RGB LED,我想让它们显示随机颜色。
我的第一个方法是从 0-360 中选择一个随机色调 h,创建一个形式为 (h 的 HSV 颜色, 1, 1), 然后使用 the algorithm given on Wikipedia 从 HSV 转换为 RGB。这几乎可以满足我的要求,但不完全是。
问题是 LED 可能看起来更亮或更暗,具体取决于色调。我希望它始终显示相同的亮度,无论色调如何。
因此,例如,蓝色在 RGB space 中为 (0, 0, 1),而青色为 (0, 1, 1)。如果我们做出所有三个原色都同样亮的简化假设,那么青色的亮度是蓝色的两倍。
我想要的是 RGB space 中的蓝色为 (0, 0, 1),青色为 (0, 0.5, 0.5),因此原色之和始终为1.0.
我可以用这样的算法很容易地破解一些东西:
- 选择一个介于 0 和 1 之间的值 x。
- 选择三个原色之一,并将其设置为 x。
- 选择剩下的两个初选之一,并将其设置为 1 - x.
- 将第三个主要设置为 0。
我的问题是:是否有更原则的方法来做到这一点?是否有某种颜色 space 符合我的要求?
结论: @Vincent van der Weele 具有我需要规范化的重要洞察力。 @Stefan Haustein 的 luma 是表达同一事物的另一种方式,同时还为不同的初选添加了不同的权重。但是,那些特殊的权重在我的情况下不起作用。在实验上,我为 R、G 和 B 选择了 0.3、0.25 和 0.2 的权重。同样在实验上,我选择了 2.0 的伽马(与我最初使用的 2.8 相反)。这仍然不完美,但比以前好多了。我想这自然是乱七八糟的。
我会将亮度设为光谱中最暗的颜色(= 蓝色,0.0722)。然后缩放计算出的 RGB 值,使生成的亮度与该值匹配。参见 https://en.wikipedia.org/wiki/Luma_(video)
luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
// factor * luma = 0.0722
factor = 0.0722 / luma;
r *= factor;
g *= factor;
b *= factor;
P.S。根据您的简化假设,这将是
luma = (r + g + b) / 3.0;
factor = 1.0 / (3.0 * luma);
r *= factor;
g *= factor;
b *= factor;
将总亮度归一化为单个分量的亮度(1/3)
你说得对,黄色、青色和品红色的组合颜色比红色、绿色和蓝色三原色更亮。您可以在 HSV 生成的色调的简单图中看到这一点(我相信 HSL 看起来是一样的):
它们更亮,但不是两倍。那是因为眼睛对光的反应 power-law function. Taking the intensity to the power of 0.43 最接近你眼睛看到的东西;这意味着黄色、青色和品红色的亮度只有 1.35 倍。
还有一个因素需要考虑。 HSV 公式正在生成 sRGB 值,其 gamma correction factor 约为 2.2 - 这些值与产生的光量不是线性关系。您的 LED 可能 是 线性的,因此它们看起来会有所不同:
呸!显然,驱动 LED 的值需要采用线性颜色 space,而不是 sRGB。
为了保持恒定的亮度,power-law space 中所有颜色的总和需要保持恒定。您可以通过将幂律应用于线性 r、g、b 强度,然后在总和上缩放 r、g、b 来实现这一点。取幂律的倒数将值恢复为线性 RGB。
这是一些实际的 Python 代码和生成的图像。 r、g、b 值从线性转换为 sRGB 以生成图像文件,但为了清楚起见,我将其省略。我根据standard sRGB linearity conversions.
自己写的srgb2.from_sRGB
函数
r,g,b = colorsys.hsv_to_rgb(angle/360, 1.0, 1.0)
r,g,b = srgb2.from_sRGB([r*255,g*255,b*255])
gamma = .43
r,g,b = r**(1/gamma), g**(1/gamma), b**(1/gamma)
t = r + g + b
r = r / t
g = g / t
b = b / t
r,g,b = r**gamma, g**gamma, b**gamma
没有亮点了!
我有一些 RGB LED,我想让它们显示随机颜色。
我的第一个方法是从 0-360 中选择一个随机色调 h,创建一个形式为 (h 的 HSV 颜色, 1, 1), 然后使用 the algorithm given on Wikipedia 从 HSV 转换为 RGB。这几乎可以满足我的要求,但不完全是。
问题是 LED 可能看起来更亮或更暗,具体取决于色调。我希望它始终显示相同的亮度,无论色调如何。
因此,例如,蓝色在 RGB space 中为 (0, 0, 1),而青色为 (0, 1, 1)。如果我们做出所有三个原色都同样亮的简化假设,那么青色的亮度是蓝色的两倍。
我想要的是 RGB space 中的蓝色为 (0, 0, 1),青色为 (0, 0.5, 0.5),因此原色之和始终为1.0.
我可以用这样的算法很容易地破解一些东西:
- 选择一个介于 0 和 1 之间的值 x。
- 选择三个原色之一,并将其设置为 x。
- 选择剩下的两个初选之一,并将其设置为 1 - x.
- 将第三个主要设置为 0。
我的问题是:是否有更原则的方法来做到这一点?是否有某种颜色 space 符合我的要求?
结论: @Vincent van der Weele 具有我需要规范化的重要洞察力。 @Stefan Haustein 的 luma 是表达同一事物的另一种方式,同时还为不同的初选添加了不同的权重。但是,那些特殊的权重在我的情况下不起作用。在实验上,我为 R、G 和 B 选择了 0.3、0.25 和 0.2 的权重。同样在实验上,我选择了 2.0 的伽马(与我最初使用的 2.8 相反)。这仍然不完美,但比以前好多了。我想这自然是乱七八糟的。
我会将亮度设为光谱中最暗的颜色(= 蓝色,0.0722)。然后缩放计算出的 RGB 值,使生成的亮度与该值匹配。参见 https://en.wikipedia.org/wiki/Luma_(video)
luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
// factor * luma = 0.0722
factor = 0.0722 / luma;
r *= factor;
g *= factor;
b *= factor;
P.S。根据您的简化假设,这将是
luma = (r + g + b) / 3.0;
factor = 1.0 / (3.0 * luma);
r *= factor;
g *= factor;
b *= factor;
将总亮度归一化为单个分量的亮度(1/3)
你说得对,黄色、青色和品红色的组合颜色比红色、绿色和蓝色三原色更亮。您可以在 HSV 生成的色调的简单图中看到这一点(我相信 HSL 看起来是一样的):
它们更亮,但不是两倍。那是因为眼睛对光的反应 power-law function. Taking the intensity to the power of 0.43 最接近你眼睛看到的东西;这意味着黄色、青色和品红色的亮度只有 1.35 倍。
还有一个因素需要考虑。 HSV 公式正在生成 sRGB 值,其 gamma correction factor 约为 2.2 - 这些值与产生的光量不是线性关系。您的 LED 可能 是 线性的,因此它们看起来会有所不同:
呸!显然,驱动 LED 的值需要采用线性颜色 space,而不是 sRGB。
为了保持恒定的亮度,power-law space 中所有颜色的总和需要保持恒定。您可以通过将幂律应用于线性 r、g、b 强度,然后在总和上缩放 r、g、b 来实现这一点。取幂律的倒数将值恢复为线性 RGB。
这是一些实际的 Python 代码和生成的图像。 r、g、b 值从线性转换为 sRGB 以生成图像文件,但为了清楚起见,我将其省略。我根据standard sRGB linearity conversions.
自己写的srgb2.from_sRGB
函数
r,g,b = colorsys.hsv_to_rgb(angle/360, 1.0, 1.0)
r,g,b = srgb2.from_sRGB([r*255,g*255,b*255])
gamma = .43
r,g,b = r**(1/gamma), g**(1/gamma), b**(1/gamma)
t = r + g + b
r = r / t
g = g / t
b = b / t
r,g,b = r**gamma, g**gamma, b**gamma
没有亮点了!