我正在寻找某种公式或算法来确定给定RGB值的颜色的亮度.我知道它不能像将RGB值一起添加并且具有更高的总和更简单一样简单,但我有点不知道从哪里开始.
你的意思是亮度?感知亮度?亮度?
亮度(某些色彩空间的标准):(0.2126*R + 0.7152*G + 0.0722*B)
[1]
亮度(感知选项1):(0.299*R + 0.587*G + 0.114*B)
[2]
亮度(感知选项2,计算速度较慢): → sqrt( 0.241*R^2 + 0.691*G^2 + 0.068*B^2 )
sqrt( 0.299*R^2 + 0.587*G^2 + 0.114*B^2 )
(感谢@MatthewHerbst)[3]
我认为你要找的是RGB - > Luma转换公式.
光度/数字ITU BT.709:
Y = 0.2126 R + 0.7152 G + 0.0722 B
数字ITU BT.601(对R和B组件给予更多权重):
Y = 0.299 R + 0.587 G + 0.114 B
如果您愿意为性能交换准确度,则有两个近似公式:
Y = 0.33 R + 0.5 G + 0.16 B Y = 0.375 R + 0.5 G + 0.125 B
这些可以快速计算
Y = (R+R+B+G+G+G)/6 Y = (R+R+R+B+G+G+G+G)>>3
我在接受的答案中对三种算法进行了比较.我在循环中生成了颜色,其中仅使用了大约每400种颜色.每种颜色由2x2像素表示,颜色从最暗到最轻(从左到右,从上到下)排序.
第1张图片 - 亮度(相对)
0.2126 * R + 0.7152 * G + 0.0722 * B
第二张图片 - http://www.w3.org/TR/AERT#color-contrast
0.299 * R + 0.587 * G + 0.114 * B
第3张图片 - HSP颜色模型
sqrt(0.299 * R^2 + 0.587 * G^2 + 0.114 * B^2)
第4张图片 - WCAG 2.0 SC 1.4.3 相对亮度和对比度公式(参见@ Synchro的答案)
根据一行中的颜色数量,有时可以在第1张和第2张照片上发现图案.我从未在第3或第4算法的图片上发现任何图案.
如果我不得不选择我会使用算法3,因为它更容易实现,比第4快约33%.
下面是唯一用于将sRGB图像(如在浏览器等中使用)转换为灰度的CORRECT算法.
在计算内积之前,必须对颜色空间应用伽马函数的逆.然后将gamma函数应用于减少的值.未能合并伽玛功能可能导致高达20%的误差.
对于典型的计算机内容,颜色空间为sRGB.sRGB的正确数字是约.0.21,0.72,0.07.用于sRGB的Gamma是一个复合函数,其近似指数乘以1 /(2.2).这是C++中的全部内容.
// sRGB luminance(Y) values const double rY = 0.212655; const double gY = 0.715158; const double bY = 0.072187; // Inverse of sRGB "gamma" function. (approx 2.2) double inv_gam_sRGB(int ic) { double c = ic/255.0; if ( c <= 0.04045 ) return c/12.92; else return pow(((c+0.055)/(1.055)),2.4); } // sRGB "gamma" function (approx 2.2) int gam_sRGB(double v) { if(v<=0.0031308) v *= 12.92; else v = 1.055*pow(v,1.0/2.4)-0.055; return int(v*255+0.5); // This is correct in C++. Other languages may not // require +0.5 } // GRAY VALUE ("brightness") int gray(int r, int g, int b) { return gam_sRGB( rY*inv_gam_sRGB(r) + gY*inv_gam_sRGB(g) + bY*inv_gam_sRGB(b) ); }
唯一准确的答案是@ jive- dadson和@EddingtonsMonkey答案,并支持@ nils-pipenbrinck。其他答案(包括接受的答案)链接到或引用了错误,无关,过时或损坏的来源。
sRGB的必须线性化应用系数之前。
亮度(L或Y)与光线是线性的。
感知亮度(L *)与人类感知一样是非线性的。
就感知而言,HSV和HSL甚至都不是很准确。
sRGB的IEC标准将阈值指定为0.04045,而不是 0.03928(来自过时的早期草案)。
有用的(即相对于感知而言),欧几里得距离需要感知上统一的笛卡尔向量空间,例如CIELAB。sRGB不是一个。
由于此主题在搜索引擎中的位置很高,因此我添加了此答案以阐明对该主题的各种误解。
亮度是一种感知属性,它没有直接的度量。
感知亮度是通过某些视觉模型(例如CIELAB)测量的,此处L *(Lstar)是感知亮度的量度,并且是非线性的,可以近似人类视觉的非线性响应曲线。
亮度是光的线性度量,对正常视觉在光谱上加权,但未对非线性的亮度感知进行调整。
亮度(Y素数)是在某些视频编码中使用的伽玛编码加权信号。请勿将其与线性亮度混淆。
伽玛曲线或传输曲线(TRC)是通常与感知曲线相似的曲线,通常应用于图像数据以进行存储或广播,以减少感知到的噪声和/或提高数据利用率(及相关原因)。
要确定感知亮度,请先将经过伽玛编码的R´G´B´图像值转换为线性亮度(L
或Y
),然后再转换为非线性感知亮度(L*
)
...因为它显然丢失了...
将所有sRGB 8位整数值转换为十进制0.0-1.0
vR = sR / 255; vG = sG / 255; vB = sB / 255;
将伽玛编码的RGB转换为线性值。例如,sRGB(计算机标准)需要大约V ^ 2.2的功率曲线,尽管“准确”变换为:
其中V´是sRGB的经伽玛编码的R,G或B通道。
伪代码:
function sRGBtoLin(colorChannel) { // Send this function a decimal sRGB gamma encoded color value // between 0.0 and 1.0, and it returns a linearized value. if ( colorChannel <= 0.04045 ) { return colorChannel / 12.92; } else { return pow((( colorChannel + 0.055)/1.055),2.4)); } }
要找到亮度(Y),请对sRGB应用标准系数:
使用以上功能的伪代码:
Y = (0.2126 * sRGBtoLin(vR) + 0.7152 * sRGBtoLin(vG) + 0.0722 * sRGBtoLin(vB))
从上方获取亮度Y,然后转换为L *
伪代码:
function YtoLstar(Y) { // Send this function a luminance value between 0.0 and 1.0, // and it returns L* which is "perceptual lightness" if ( Y <= (216/24389) { // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036 return Y * (24389/27); // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296 } else { return pow(Y,(1/3)) * 116 - 16; } }
L *是从0(黑色)到100(白色)的值,其中50是可感知的“中间灰色”。L * = 50相当于Y = 18.4,或者换句话说就是18%的灰卡,代表摄影曝光的中间位置(Ansel Adams区V)。
IEC 61966-2-1:1999 Standard
Wikipedia sRGB
Wikipedia CIELAB
Wikipedia CIEXYZ
Charles Poynton的Gamma常见问题解答
我发现这个代码(用C#编写)可以很好地计算颜色的"亮度".在这种情况下,代码试图确定是否在颜色上放置白色或黑色文本.
有趣的是,RGB => HSV的这个公式只使用v = MAX3(r,g,b).换句话说,您可以使用(r,g,b)的最大值作为HSV中的V.
我检查了Hearn&Baker的第575页,这也是他们计算"价值"的方式.
我建议你选择W3C标准推荐的公式,而不是迷失在这里提到的随机选择的公式中.
这是WCAG 2.0 SC 1.4.3 相对亮度和对比度公式的简单但精确的PHP实现.它生成的值适用于评估WCAG合规性所需的比率,如本页所示,因此适用于任何Web应用程序.这对于移植到其他语言来说是微不足道的.
/** * Calculate relative luminance in sRGB colour space for use in WCAG 2.0 compliance * @link http://www.w3.org/TR/WCAG20/#relativeluminancedef * @param string $col A 3 or 6-digit hex colour string * @return float * @author Marcus Bointon*/ function relativeluminance($col) { //Remove any leading # $col = trim($col, '#'); //Convert 3-digit to 6-digit if (strlen($col) == 3) { $col = $col[0] . $col[0] . $col[1] . $col[1] . $col[2] . $col[2]; } //Convert hex to 0-1 scale $components = array( 'r' => hexdec(substr($col, 0, 2)) / 255, 'g' => hexdec(substr($col, 2, 2)) / 255, 'b' => hexdec(substr($col, 4, 2)) / 255 ); //Correct for sRGB foreach($components as $c => $v) { if ($v <= 0.03928) { $components[$c] = $v / 12.92; } else { $components[$c] = pow((($v + 0.055) / 1.055), 2.4); } } //Calculate relative luminance using ITU-R BT. 709 coefficients return ($components['r'] * 0.2126) + ($components['g'] * 0.7152) + ($components['b'] * 0.0722); } /** * Calculate contrast ratio acording to WCAG 2.0 formula * Will return a value between 1 (no contrast) and 21 (max contrast) * @link http://www.w3.org/TR/WCAG20/#contrast-ratiodef * @param string $c1 A 3 or 6-digit hex colour string * @param string $c2 A 3 or 6-digit hex colour string * @return float * @author Marcus Bointon */ function contrastratio($c1, $c2) { $y1 = relativeluminance($c1); $y2 = relativeluminance($c2); //Arrange so $y1 is lightest if ($y1 < $y2) { $y3 = $y1; $y1 = $y2; $y2 = $y3; } return ($y1 + 0.05) / ($y2 + 0.05); }
添加所有其他人说的话:
所有这些方程在实际工作有点儿好,但如果你需要非常精确,你必须首先将颜色转换为线性颜色空间(应用逆图像-γ),做重均原色和 - 如果你想显示颜色 - 将亮度恢复到显示器伽玛.
在深灰色中,瞄准伽玛和进行适当伽玛之间的亮度差异高达20%.