题
我正在寻找某种公式或算法,以确定给定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像素表示,颜色从最黑到最轻(从左到右,上到底部)排序。
第一张图片 - 亮度(相对)
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
第三张图片 - HSP颜色模型
sqrt(0.299 * R^2 + 0.587 * G^2 + 0.114 * B^2)
第四张图片 - WCAG 2.0 SC 1.4.3 相对亮度 和 对比度 公式(见 @Synchro的 回答 这里)
有时可以根据一行的颜色数量在第一和第二图上发现图案。我从未从第三算法或第四算法上发现任何图案。
如果我不得不选择,我将使用算法第3算法,因为它更容易实现,并且比第四算法快33%。
下面是将SRGB图像(如浏览器等)转换为灰度的唯一正确的算法。
在计算内部产品之前,有必要在颜色空间中应用伽马函数的倒数。然后,将伽马函数应用于降低值。未能合并伽马功能可能会导致高达20%的错误。
对于典型的计算机内容,颜色空间为SRGB。 SRGB的正确数字约为。 0.21、0.72、0.07。 SRGB的伽马是一个复合函数,可近似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)
);
}
有趣的是, RGB => HSV的该公式 仅使用V = Max3(R,G,B)。换句话说,您可以使用 最大 (r,g,b)为HSV中的V。
我检查了一下,并在第575页 Hearn&Baker 这也是他们计算“价值”的方式。
我发现 此代码 (用C#编写)在计算颜色的“亮度”方面做得很好。在这种情况下,代码试图确定是否将白色或黑色文本放在颜色上。
添加其他所有人所说的话:
所有这些方程在实践中有点很好,但是如果您需要非常确切地说,则必须先将颜色转换为线性颜色空间(应用倒数图像伽马),请执行原色平均值,如果您想 - 显示颜色 - 将亮度带回监视器伽玛。
在黑暗的灰色灰色中,添加伽玛和做适当的伽玛之间的亮度差异高达20%。
我建议您选择W3C标准推荐的公式。
这是直接但精确的PHP实现 WCAG 2.0 SC 1.4.3 相对亮度 和 对比度 公式。它产生的值适合评估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.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 <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);
}
“接受的”答案是不正确且不完整的
唯一准确的答案是 @jive-dadson 和 @eddingtonsmonkey 答案和支持 @nils-pipenbrinck. 。其他答案 (包括接受的) 正在链接到或引用错误,无关紧要,过时或破坏的来源。
简要地:
- SRGB必须是 线性化 在应用系数之前。
- 亮度(l或y)是线性的。
- 感知的轻度(L*)是人类的非线性。
- 在感知方面,HSV和HSL甚至都不是遥不可及的。
- SRGB的IEC标准指定的阈值为0.04045是 不是 0.03928(那是来自过时的早期草稿)。
- 有用 (IE相对于感知), ,欧几里得距离需要一个感知均匀的笛卡尔载体空间,例如Cielab。 SRGB不是一个。
以下是一个正确而完整的答案:
因为该线程在搜索引擎中表现很高,所以我添加了此答案,以阐明对该主题的各种误解。
亮度 是一个感知属性,没有直接度量。
感知的轻度 通过某些视觉模型(例如Cielab)来衡量,这里的L*(LSTAR)是衡量的 感知轻度, ,并且是非线性的,无法近似人类视力非线性响应曲线。
亮度 是光线的线性度量,以频谱为正常视力,但没有针对非线性感知轻度调整。
Luma (是的 Prime)是在某些视频编码中使用的伽马编码,加权信号。它不要与线性亮度混淆。
伽玛 或转移曲线(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)的伽马常见问题解答
HSV Colorspace应该可以解决问题,看看 维基百科文章 根据您使用的语言,您可能会得到库转换。
H是色相,是颜色的数值(即红色,绿色...)
S是颜色的饱和,即它是多么强烈
v是颜色的“亮度”。
RGB亮度值= 0.3 r + 0.59 g + 0.11 b
http://www.scantips.com/lumin.html
如果您正在寻找颜色离白色有多近的颜色,则可以使用欧几里得距离(255、255、255)
我认为相对于L2欧几里得距离,RGB颜色空间感知不均匀。统一空间包括CIE实验室和LUV。
Jive Dadson的逆伽马公式需要在JavaScript中实现半个调整,即返回function gam_srgb的返回int int(v*255);不返回int(v*255+.5);半个调整圆形,这可能会导致一个值在r = g = b = b = b = b = b = b灰色三合会上的值。 r = g = b三合会上的灰度转换应产生等于r的值;这是公式有效的证明。看 九种灰度的阴影 用于行动中的公式(没有半个调整)。
这是一些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
}
我想知道如何确定这些RGB系数。我自己做了一个实验,最终得到了以下内容:
Y = 0.267 R + 0.642 G + 0.091 B
接近但显然与长期建立的ITU系数不同。我想知道每个观察者的系数是否可能有所不同,因为我们眼睛中的视网膜上可能有不同数量的锥和杆,尤其是不同类型的锥体之间的比率可能有所不同。
以供参考:
ITU BT.709:
Y = 0.2126 R + 0.7152 G + 0.0722 B
ITU BT.601:
Y = 0.299 R + 0.587 G + 0.114 B
我通过在鲜红色,明亮的绿色和明亮的蓝色背景上快速移动一个小的灰色条来进行测试,并调整灰色,直到尽可能多地混合。我还用其他阴影重复了该测试。我在不同的显示器上重复了测试,即使是固定伽马系数为3.0,但对我来说一切都一样。更重要的是,ITU系数从字面上看我的眼睛是错误的。
是的,我大概有正常的色彩视觉。
请定义亮度。如果您正在寻找颜色有多近的白色,则可以使用 欧几里得距离 从(255、255、255)
HSV的“ V”可能是您想要的。 MATLAB具有RGB2HSV函数,先前引用的Wikipedia文章充满了伪代码。如果RGB2HSV转换不可行,那么较不准确的模型将是图像的灰度版本。
这个链接 解释所有内容,包括为什么这些乘数常数在R,G和B值之前存在。
编辑:它也对这里的答案之一有解释(0.299*r + 0.587*g + 0.114*b)
To determine the brightness of a color with R, I convert the RGB system color in HSV system color.
In my script, I use the HEX system code before for other reason, but you can start also with RGB system code with rgb2hsv {grDevices}
. The documentation is here.
Here is this part of my code:
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
For clarity, the formulas that use a square root need to be
sqrt(coefficient * (colour_value^2))
not
sqrt((coefficient * colour_value))^2
The proof of this lies in the conversion of a R=G=B triad to greyscale R. That will only be true if you square the colour value, not the colour value times coefficient. See Nine Shades of Greyscale