我正在寻找某种公式或算法来确定给定RGB值的颜色的亮度。我知道这不像把RGB值加在一起那么简单,更高的总和更亮,但我有点不知所措,不知道从哪里开始。


当前回答

正如@Nils Pipenbrinck所提到的:

所有这些方程在实践中都很有效,但如果你需要非常精确,你就必须[做一些额外的gamma东西]。在深灰色中,忽略伽玛和正确伽玛之间的亮度差异高达20%。

这里有一个完全自包含的JavaScript函数,它做了“额外的”工作来获得额外的准确性。它基于Jive Dadson对这个问题的c++回答。

// Returns greyscale "brightness" (0-1) of the given 0-255 RGB values
// Based on this C++ implementation: https://stackoverflow.com/a/13558570/11950764
function rgbBrightness(r, g, b) {
  let v = 0;
  v += 0.212655 * ((r/255) <= 0.04045 ? (r/255)/12.92 : Math.pow(((r/255)+0.055)/1.055, 2.4));
  v += 0.715158 * ((g/255) <= 0.04045 ? (g/255)/12.92 : Math.pow(((g/255)+0.055)/1.055, 2.4));
  v += 0.072187 * ((b/255) <= 0.04045 ? (b/255)/12.92 : Math.pow(((b/255)+0.055)/1.055, 2.4));
  return v <= 0.0031308 ? v*12.92 : 1.055 * Math.pow(v,1.0/2.4) - 0.055;
}

请参阅Myndex的答案以获得更准确的计算。

其他回答

HSV色彩空间应该做的把戏,看维基百科文章取决于你正在工作的语言,你可能会得到一个库转换。

H是色调,是颜色的数值(即红色,绿色…)

S是颜色的饱和度,即它有多“强烈”

V是颜色的亮度。

请定义亮度。如果你想知道颜色有多接近白色你可以用欧几里得距离(255,255,255)

把这看作是对Myndex的精彩回答的补充。正如他(和其他人)解释的那样,计算RGB颜色的相对亮度(和感知亮度)的算法是设计用于线性RGB值的。你不能只是将它们应用到原始sRGB值上,并希望得到相同的结果。

理论上,这一切听起来都很棒,但我真的需要亲眼看看证据,所以,受到彼得·赫塔克(Petr Hurtak)的颜色渐变的启发,我自己做了一个。它们说明了两种最常见的算法(ITU-R建议BT.601和BT.709),并清楚地说明了为什么应该使用线性值(而不是伽玛校正值)进行计算。

首先,下面是旧的ITU BT.601算法的结果。左边的使用原始sRGB值。右边的使用线性值。

ITU-R BT.601颜色亮度梯度

0.299 r + 0.587 g + 0.114 b

在这个分辨率下,左边的照片实际上看起来非常好!但如果你仔细观察,你会发现一些问题。在更高的分辨率下,不需要的人工制品更加明显:

线性的不受这些影响,但是有很多干扰。让我们将其与ITU-R建议BT.709进行比较……

ITU-R BT.709颜色亮度梯度

0.2126 r + 0.7152 g + 0.0722 b

哦男孩。显然不打算与原始sRGB值一起使用!然而,这正是大多数人所做的!

在高分辨率下,你可以真正看到这个算法在使用线性值时是多么有效。它没有之前那个那么多噪音。虽然这些算法都不是完美的,但这个算法已经是最好的了。

亮度值= 0.3 R + 0.59 G + 0.11 B

http://www.scantips.com/lumin.html

如果你想知道颜色有多接近白色你可以用欧几里得距离(255,255,255)

我认为RGB颜色空间相对于L2欧几里得距离在感知上是不均匀的。 统一空间包括CIE LAB和LUV。

这里有一小段C代码,可以正确地计算可感知的亮度。

// reverses the rgb gamma
#define inverseGamma(t) (((t) <= 0.0404482362771076) ? ((t)/12.92) : pow(((t) + 0.055)/1.055, 2.4))

//CIE L*a*b* f function (used to convert XYZ to L*a*b*)  http://en.wikipedia.org/wiki/Lab_color_space
#define LABF(t) ((t >= 8.85645167903563082e-3) ? powf(t,0.333333333333333) : (841.0/108.0)*(t) + (4.0/29.0))


float
rgbToCIEL(PIXEL p)
{
   float y;
   float r=p.r/255.0;
   float g=p.g/255.0;
   float b=p.b/255.0;

   r=inverseGamma(r);
   g=inverseGamma(g);
   b=inverseGamma(b);

   //Observer = 2°, Illuminant = D65 
   y = 0.2125862307855955516*r + 0.7151703037034108499*g + 0.07220049864333622685*b;

   // At this point we've done RGBtoXYZ now do XYZ to Lab

   // y /= WHITEPOINT_Y; The white point for y in D65 is 1.0

    y = LABF(y);

   /* This is the "normal conversion which produces values scaled to 100
    Lab.L = 116.0*y - 16.0;
   */
   return(1.16*y - 0.16); // return values for 0.0 >=L <=1.0
}