我正在寻找某种公式或算法来确定给定RGB值的颜色的亮度。我知道这不像把RGB值加在一起那么简单,更高的总和更亮,但我有点不知所措,不知道从哪里开始。
当前回答
与其迷失在这里提到的随机选择的公式中,我建议您使用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 <marcus@synchromedia.co.uk>
*/
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.04045) {
$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 <marcus@synchromedia.co.uk>
*/
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);
}
其他回答
为了用R确定颜色的亮度,我将RGB系统颜色转换为HSV系统颜色。
在我的脚本中,我之前因为其他原因使用了HEX系统代码,但你也可以从rgb2hsv {grDevices}的RGB系统代码开始。文档在这里。
这是我的代码的这一部分:
sample <- c("#010101", "#303030", "#A6A4A4", "#020202", "#010100")
hsvc <-rgb2hsv(col2rgb(sample)) # convert HEX to HSV
value <- as.data.frame(hsvc) # create data.frame
value <- value[3,] # extract the information of brightness
order(value) # ordrer the color by brightness
为了清晰起见,使用平方根的公式必须是
√(系数* (colour_value^2))
not
√(系数*颜色值)^2
证明这一点的证据在于将R=G=B三位一体转换为灰度R。只有当你将颜色值平方,而不是颜色值乘以系数时,这才成立。参见灰色的九种色调
“接受”的答案是不正确和不完整的
唯一准确的答案是@ ji- dadson和@EddingtonsMonkey的答案,并支持@ niles -pipenbrinck。其他答案(包括已接受的答案)链接到或引用了错误的、不相关的、过时的或坏的来源。
简要:
sRGB必须在应用系数之前线性化。 亮度(L或Y)与光一样是线性的。 感知亮度(L*)与人类感知一样是非线性的。 HSV和HSL在感知方面甚至远不准确。 sRGB的IEC标准指定阈值为0.04045,而不是0.03928(这是来自过时的早期草案)。 为了有用(即相对于感知),欧几里得距离需要一个感知一致的笛卡尔向量空间,如CIELAB。sRGB不是其中之一。
以下是正确而完整的回答:
由于这条线索在搜索引擎中出现频率很高,我添加了这个答案来澄清关于这个主题的各种误解。
亮度是光的线性测量,对正常视力进行光谱加权,但对亮度的非线性感知不进行调整。它可以是相对度量,如CIEXYZ中的Y,或L, cd/m2的绝对度量(不要与L*混淆)。
一些视觉模型如CIELAB使用感知明度,这里L* (Lstar)为感知明度值,且为非线性,以近似人类视觉非线性响应曲线。(也就是说,对知觉是线性的,但因此对光是非线性的)。
亮度是一种感知属性,它不具有“物理”度量。然而,一些颜色外观模型确实有一个值,通常用“Q”表示感知亮度,这与感知亮度不同。
Luma (Y´')是一种伽玛编码的加权信号,用于某些视频编码(Y´I´Q´)。不要与线性亮度混淆。
Gamma或传递曲线(TRC)是一种通常与感知曲线相似的曲线,通常用于存储或广播图像数据,以减少感知噪声和/或提高数据利用率(以及相关原因)。
为了确定感知亮度,首先将gamma编码的R´G´B´图像值转换为线性亮度(L或Y),然后转换为非线性感知亮度(L*)
寻找亮度:
...因为很明显它在某个地方丢失了……
第一步:
将所有sRGB 8位整数值转换为十进制0.0-1.0
vR = sR / 255;
vG = sG / 255;
vB = sB / 255;
第二步:
将gamma编码的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%的灰卡,代表一张照片曝光的中间(安塞尔·亚当斯V区)。
引用:
IEC 61966-2-1:1999标准 维基百科sRGB 维基百科CIELAB 维基百科CIEXYZ Charles Poynton的Gamma常见问题解答
方法可以根据您的需要而有所不同。以下是计算亮度的3种方法:
亮度(某些颜色空间的标准):(0.2126*R + 0.7152*G + 0.0722*B)光源 亮度(感知选项1):(0.299*R + 0.587*G + 0.114*B)光源 亮度(感知选项2,计算较慢):根号(0.241*R^2 + 0.691*G^2 + 0.068*B^2)→根号(0.299*R^2 + 0.587*G^2 + 0.114*B^2)(感谢@MatthewHerbst)来源
[编辑:添加了使用命名css颜色的例子,按每种方法排序。]
下面是将sRGB图像转换为灰度的唯一正确算法,如在浏览器等中使用。
在计算内积之前,有必要对颜色空间应用伽玛函数的逆。然后你把函数应用到减少的值上。未能合并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)
);
}