如何确定颜色的感知亮度?

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">&nbsp;&nbsp;&nbsp;</span>
<span class="c" style="background-color: #2c3b4c">&nbsp;&nbsp;&nbsp;</span>
<span class="c" style="background-color: #920f1e">&nbsp;&nbsp;&nbsp;</span>
<span class="c" style="background-color: #c3313d">&nbsp;&nbsp;&nbsp;</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 (有关这些值的背景,请参阅史蒂文斯)