如何确定颜色的感知亮度?
How to determine colors perceived brightness?
我看了很多,很全post:Formula to determine brightness of RGB color
令我困扰的是,即使使用所有这些公式,我也无法得到很好的结果...这很麻烦,因为我想在调色板中从最暗到最亮对颜色进行排序。排序不对的话,看的很快很蛋疼
公式的简单示例:(0.2126*R + 0.7152*G + 0.0722*B) 这似乎是网络上最常见的答案。
在彼得回答后编辑
function colorCodeToRGB(colorCode) {
colorCode = colorCode.substr(1);
return [
colorCode.substr(0, 2),
colorCode.substr(2, 2),
colorCode.substr(4, 2)
].map(it => parseInt(it, 16));
}
const luminanceCoefficients = [.2126, .7152, .0722];
function getLuminance(color) {
const [r, g, b] = colorCodeToRGB(color);
return r * luminanceCoefficients[0] + g * luminanceCoefficients[1] + b * luminanceCoefficients[2];
}
function linearizeSRGB(colorChannel) {
colorChannel /= 255;
if (colorChannel <= .04045 ) {
return colorChannel / 12.92;
} else {
return Math.pow((colorChannel + .055)/1.055, 2.4);
}
}
console.log('First set of colors');
console.log('#1883b1', getLuminance('#1883b1'));
console.log('#2c3b4c', getLuminance('#2c3b4c'));
console.log('Second set of colors');
console.log('#920f1e', getLuminance('#920f1e'));
console.log('#c3313d', getLuminance('#c3313d'));
.c {
height: 2rem;
width: 2rem;
}
Sample of colors
<span class="c" style="background-color: #1883b1"> </span>
<span class="c" style="background-color: #2c3b4c"> </span>
<span class="c" style="background-color: #920f1e"> </span>
<span class="c" style="background-color: #c3313d"> </span>
大家可以看到,第一个蓝色比第二个浅,数值小,虽然在第二组上,第一个红色看起来比第二个深,虽然数值小...
我不明白,有什么方法可以实际确定感知亮度吗?
我测试了这个问题开头提到的 post 上的所有公式,并且通过滑动颜色选择器,我总能找到说明问题的有趣案例。我没有任何限制,我可以使用 HSL、RGB、CIELAB 等等!
提前致谢!
显然您的实施至少有两个问题。
首先是^
运算符(在^2.4
中)不是JavaScript中的幂运算符,而是"exclusive-or"运算符。将该运算符所在的行替换为以下内容。
return Math.pow(((colorChannel + .055)/1.055), 2.4);
另外,getLuminance
方法实现不正确;这样做的主要原因可能是 reduce
方法,它可能令人困惑,至少对我来说是这样。用以下内容替换该实现(它使用更简单的 map
以及直接加法和乘法):
function getLuminance(color) {
var cv=colorCodeToRGB(color).map(v=>linearizeSRGB(v))
return cv[0]*luminanceCoefficients[0]+
cv[1]*luminanceCoefficients[1]+
cv[2]*luminanceCoefficients[2]
}
超简单的 sRGB 到感知亮度
将 sRGB(作为整数 R、G、B)转换为感知亮度 (~ L*) 的超级简单的 JS 函数。这是最简单的简化方法,应该可以为大多数一般用例提供合理的预测。
function lightness(Rint,Gint,Bint) { // takes sRGB channels as 8 bit integers
var Rlin = (Rint / 255.0) ** 2.218; // Convert int to decimal 0-1 and linearize
var Glin = (Gint / 255.0) ** 2.218; // ** is the exponentiation operator, older JS needs Math.pow() instead
var Blin = (Bint / 255.0) ** 2.218; // 2.218 Gamma for sRGB linearization. 2.218 sets unity with the piecewise sRGB at #777 .... 2.2 or 2.223 could be used instead
var Ylum = Rlin * 0.2126 + Glin * 0.7156 + Blin * 0.0722; // convert to Luminance Y
return Math.pow(Ylum, 0.43) * 100; // Convert to lightness (0 to 100)
}
熟悉 sRGB 和 CIELAB 的人会注意到这里删除了具有接近黑色线性度的分段函数。这样做是为了简单起见。在实践中,这是可行的,因为我们通常对明视觉的感知亮度感兴趣,而不是非常暗的值。
return 中的 0.43 指数适用于大多数情况,但如果您要比较大面积(大块颜色),您可以将它降低到低至 0.33,或者如果试图预测亮度对于微小的光点,您可以将其提高到 0.5 (有关这些值的背景,请参阅史蒂文斯)
我看了很多,很全post:Formula to determine brightness of RGB color
令我困扰的是,即使使用所有这些公式,我也无法得到很好的结果...这很麻烦,因为我想在调色板中从最暗到最亮对颜色进行排序。排序不对的话,看的很快很蛋疼
公式的简单示例:(0.2126*R + 0.7152*G + 0.0722*B) 这似乎是网络上最常见的答案。
在彼得回答后编辑
function colorCodeToRGB(colorCode) {
colorCode = colorCode.substr(1);
return [
colorCode.substr(0, 2),
colorCode.substr(2, 2),
colorCode.substr(4, 2)
].map(it => parseInt(it, 16));
}
const luminanceCoefficients = [.2126, .7152, .0722];
function getLuminance(color) {
const [r, g, b] = colorCodeToRGB(color);
return r * luminanceCoefficients[0] + g * luminanceCoefficients[1] + b * luminanceCoefficients[2];
}
function linearizeSRGB(colorChannel) {
colorChannel /= 255;
if (colorChannel <= .04045 ) {
return colorChannel / 12.92;
} else {
return Math.pow((colorChannel + .055)/1.055, 2.4);
}
}
console.log('First set of colors');
console.log('#1883b1', getLuminance('#1883b1'));
console.log('#2c3b4c', getLuminance('#2c3b4c'));
console.log('Second set of colors');
console.log('#920f1e', getLuminance('#920f1e'));
console.log('#c3313d', getLuminance('#c3313d'));
.c {
height: 2rem;
width: 2rem;
}
Sample of colors
<span class="c" style="background-color: #1883b1"> </span>
<span class="c" style="background-color: #2c3b4c"> </span>
<span class="c" style="background-color: #920f1e"> </span>
<span class="c" style="background-color: #c3313d"> </span>
大家可以看到,第一个蓝色比第二个浅,数值小,虽然在第二组上,第一个红色看起来比第二个深,虽然数值小...
我不明白,有什么方法可以实际确定感知亮度吗?
我测试了这个问题开头提到的 post 上的所有公式,并且通过滑动颜色选择器,我总能找到说明问题的有趣案例。我没有任何限制,我可以使用 HSL、RGB、CIELAB 等等!
提前致谢!
显然您的实施至少有两个问题。
首先是^
运算符(在^2.4
中)不是JavaScript中的幂运算符,而是"exclusive-or"运算符。将该运算符所在的行替换为以下内容。
return Math.pow(((colorChannel + .055)/1.055), 2.4);
另外,getLuminance
方法实现不正确;这样做的主要原因可能是 reduce
方法,它可能令人困惑,至少对我来说是这样。用以下内容替换该实现(它使用更简单的 map
以及直接加法和乘法):
function getLuminance(color) {
var cv=colorCodeToRGB(color).map(v=>linearizeSRGB(v))
return cv[0]*luminanceCoefficients[0]+
cv[1]*luminanceCoefficients[1]+
cv[2]*luminanceCoefficients[2]
}
超简单的 sRGB 到感知亮度
将 sRGB(作为整数 R、G、B)转换为感知亮度 (~ L*) 的超级简单的 JS 函数。这是最简单的简化方法,应该可以为大多数一般用例提供合理的预测。
function lightness(Rint,Gint,Bint) { // takes sRGB channels as 8 bit integers
var Rlin = (Rint / 255.0) ** 2.218; // Convert int to decimal 0-1 and linearize
var Glin = (Gint / 255.0) ** 2.218; // ** is the exponentiation operator, older JS needs Math.pow() instead
var Blin = (Bint / 255.0) ** 2.218; // 2.218 Gamma for sRGB linearization. 2.218 sets unity with the piecewise sRGB at #777 .... 2.2 or 2.223 could be used instead
var Ylum = Rlin * 0.2126 + Glin * 0.7156 + Blin * 0.0722; // convert to Luminance Y
return Math.pow(Ylum, 0.43) * 100; // Convert to lightness (0 to 100)
}
熟悉 sRGB 和 CIELAB 的人会注意到这里删除了具有接近黑色线性度的分段函数。这样做是为了简单起见。在实践中,这是可行的,因为我们通常对明视觉的感知亮度感兴趣,而不是非常暗的值。
return 中的 0.43 指数适用于大多数情况,但如果您要比较大面积(大块颜色),您可以将它降低到低至 0.33,或者如果试图预测亮度对于微小的光点,您可以将其提高到 0.5 (有关这些值的背景,请参阅史蒂文斯)