确定RGB颜色亮度的公式


387

我正在寻找某种公式或算法来确定给定RGB值的颜色的亮度。我知道这不像将RGB值相加并使总和更高更明亮一样简单,但是我对于从何处开始感到困惑。


8
感觉到的亮度是我想要的,谢谢。
robmerica

2
有一篇很好的文章(在.NET中处理颜色-第1部分)中有关颜色空间以及它们之间的对话(包括理论和代码(C#))。要获得答案,请参阅本文中的“ 模型之间的转换”主题。
下划线

4
我已经有很多年了,但我从未做过。我可以建议您复习答案,然后重新考虑接受哪个答案吗?
Jive Dadson

Answers:


455

你是说亮度吗?感知亮度?亮度?

  • 亮度(某些色彩空间的标准):(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]

26
请注意,这两个都强调生理方面:人眼对绿光最敏感,对红色最不敏感,对蓝色最不敏感。
鲍勃·克罗斯2009年

16
还要注意,所有这些可能都适用于线性0-1 RGB,并且您可能具有经过伽马校正的0-255 RGB。它们并没有像您认为的那样转化。
亚历克斯·古奇

4
不正确。在应用线性变换之前,必须先对色彩空间应用伽玛函数的逆函数。然后,在应用线性函数之后,将应用伽马函数。
吉夫·达德森

6
在最后一个公式中,它是(0.299 * R)^ 2还是0.299 *(R ^ 2)?
Kaizer Sozay

3
@KaizerSozay正如它在这里所写,它的意思是0.299*(R^2)(因为乘幂在乘法之前)
Dantevg

298

我认为您正在寻找的是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

47
我喜欢您输入精确的值,但还包括快速的“足够接近”类型的快捷方式。+1。
Beska

3
@Jonathan Dumaine-两个快速计算公式都包括蓝色-第一个是(2 * Red + Blue+ 3 * Green)/ 6,第二个是(3 * Red + Blue+ 4 * Green)>> 3。当然,在两种快速近似中,Blue的权重最低,但仍然存在。
弗朗西·佩诺夫

84
@JonathanDumaine那是因为人眼对蓝色的感知最少;-)
Christopher Oezbek 2012年

4
快速版本效果很好。经过测试,并应用于具有成千上万用户的真实应用程序,一切看起来都很好。
milosmns,2015年

10
如果按照以下方式进行操作,则快速版本甚至更快:(Y = (R<<1+R+G<<2+B)>>3在ARM上只有3-4个CPU周期),但是我想一个好的编译器会为您进行优化。
rjmunro

105

我在接受的答案中比较了这三种算法。我以周期方式生成颜色,其中仅使用每种第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 相对亮度对比度公式(见@同步的答案这里

有时可能会在第一张和第二张图片上发现图案,具体取决于一行中的颜色数量。我从未在第3或第4算法的图片上发现任何图案。

如果我必须选择的话,我会选择算法3,因为它更容易实现,并且比算法4快33%。

感知亮度算法比较


3
对我来说,这是最好的答案,因为oyu使用的图片模式可让您感知是否以相同的亮度渲染了不同的色调。对于我和我的电流监视器第三画面是“最好看的”,因为它也快则4日这是一个加
CoffeDeveloper

8
您的比较图像不正确,因为您没有为所有功能提供正确的输入。第一个功能需要线性 RGB输入。我只能通过提供非线性(即经过伽马校正的)RGB 来再现条纹效果。更正此问题,您不会遇到任何带状痕迹,并且第一个功能无疑是赢家。
Max

1
@Max的^2sqrt包括在第三式中的从近似线性RGB非线性RGB代替的一个更快的方式^2.2^(1/2.2)这将是更正确。不幸的是,使用非线性输入代替线性输入非常普遍。
马克·兰瑟姆

53

以下是将浏览器等中使用的sRGB图像转换为灰度的唯一正确算法。

在计算内部积之前,必须对色彩空间应用伽玛函数的逆函数。然后,将伽马函数应用于减小的值。未能合并伽玛功能可能导致高达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)
    );
}

5
这就是sRGB定义的方式。我认为原因是它避免了一些接近零的数值问题。如果只是将数字提高到2.2和1 / 2.2的幂,那不会有太大的区别。
吉夫·达德森

8
JMD-作为视觉感知实验室工作的一部分,我已经在CRT监视器上进行了直接的亮度测量,并且可以确认在值范围的底部存在线性的亮度区域。
杰里·费德斯皮尔

2
我知道这已经很老了,但是仍然需要搜索。我认为这是不正确的。灰色(255,255,255)=灰色(255,0,0)+灰色(0,255,0)+灰色(0,0,255)不应该吗?没有。
DCBillen 2015年

2
@DCBillen:否,因为这些值在经过非线性伽马校正的sRGB空间中,所以不能仅将它们相加。如果要添加它们,则应在调用gam_sRGB之前添加它们。
rdb

1
@DCBillen Rdb是正确的。函数int gray(int r,int g,int b)中显示了添加它们的方法,该函数“取消调用” gam_sRGB。四年后,正确答案的评价如此之低,这让我很痛苦。:-)不太。.我会克服的。
达德森

45

“已接受”答案不正确且不完整

唯一准确的答案是@ 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´图像值转换为线性亮度(LY),然后再转换为非线性感知亮度(L*


查找亮度:

...因为它显然丢失了...

步骤1:

将所有sRGB 8位整数值转换为十进制0.0-1.0

  vR = sR / 255;
  vG = sG / 255;
  vB = sB / 255;

第二步:

将伽玛编码的RGB转换为线性值。例如,sRGB(计算机标准)需要大约V ^ 2.2的功率曲线,尽管“准确”变换为:

sRGB转线性

其中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 = R * 0.2126 + G * 0.7152 + B * 0.0722

使用以上功能的伪代码:

Y = (0.2126 * sRGBtoLin(vR) + 0.7152 * sRGBtoLin(vG) + 0.0722 * sRGBtoLin(vB))

查找可见的亮度:

第四步:

从上方获取亮度Y,然后转换为L *

来自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常见问题解答


@Rotem谢谢您-我看到了一些奇怪且不完整的声明,并认为将其确定会有所帮助,特别是因为此线程在搜索引擎上仍然排名很高。
Myndex

我使用几个MATLAB命令比较了BT.601 LumaCIE 1976 L * Perceptual Gray,创建了一个演示Luma=rgb2gray(RGB);LAB=rgb2lab(RGB);LAB(:,:,2:3)=0;PerceptualGray=lab2rgb(LAB);
Rotem

@Myndex我使用您的公式得出L *,但是无论我使用什么公式,我仍然会得到一些奇怪的结果...与您的公式相比,#d05858的L *比#c51c2a的L *暗。正确的方法?为什么没有公式能按预期工作?:(
sjahan

1
@asdfasdfads是的,L*a*b*没有考虑许多心理物理属性。亥姆霍兹-科劳斯效应是其中之一,但还有许多其他效应。无论如何,CIELAB都不是“完整的”图像评估模型。在我的帖子中,我试图尽可能全面地涵盖基本概念,而又不冒险涉及非常深的细节。亨特(Hunt)模型,飞兆半导体(Fairchild)的模型和其他模型做得更完善,但也要复杂得多。
Myndex

1
@Myndex,没关系,我的实现是基于疲劳的,并且我的糟糕结果来自于:(非常感谢您的帮助,并且您的帖子非常有价值!
sjahan

11

我发现这段代码(用C#编写)在计算颜色的“亮度”方面做得很好。在这种情况下,代码试图确定是在颜色上放置白色还是黑色文本。


1
那正是我所需要的。我当时正在做一个经典的“彩条”演示,想用最好的黑白选择在颜色上方标记它们!
RufusVS

10

有趣的是,此RGB => HSV的公式仅使用v = MAX3(r,g,b)。换句话说,您可以将(r,g,b)的最大值用作HSV中的V。

我在Hearn&Baker的 575页上进行了检查,这也是他们计算“值”的方式。

摘自Hearn&Baker 319页


仅作记录,链接已死,此处的存档版本-web.archive.org/web/20150906055359/http://…–
Peter

HSV在感知上不是统一的(甚至不接近)。它仅用作调整颜色的“便捷”方式,但与感知无关,并且V与L或Y的真实值(CIE亮度)无关。
Myndex

9

建议您不要使用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);
}

为什么您更喜欢w3c定义?我个人已经实施了CCIR 601和w3c推荐的产品,而我对CCIR 601的结果感到更加满意
user151496 2014年

1
因为,正如我所说,W3C和WCAG都推荐它吗?
同步2014年

1
在许多级别上,W3C公式均不正确。它没有考虑到人类的感知,而是使用了“简单”的对比度,该对比度是线性的并且根本不是感知上均匀的。除其他外,它们似乎基于早于1988年的某些标准(!!!),而今天却不相关(这些标准基于单色监视器,例如绿色/黑色,并且指的是从开到关的总对比度。 ,而不考虑灰度或颜色)。
Myndex

1
那是完全垃圾。亮度特别具有感知能力-这就是为什么它对红色,绿色和蓝色具有不同的系数的原因。年龄与它无关-出色的CIE Lab感知色空间可以追溯到1976年。W3C空间虽然不那么好,但是它是易于计算的良好实用近似值。如果您有什么建设性的建议,请发表而不是空洞的批评。
同步

3
只是添加/更新:我们目前正在研究可更好地建模感知对比的替换算法(在Github第695期中进行讨论)。但是,作为一个单独的问题,仅供参考,sRGB的阈值为0.04045,而不是从过时的sRGB早期草案中引用的0.03928。权威的IEC标准使用0.04045,并且即将提出拉取请求以更正WCAG中的此错误。(参考:IEC 61966-2-1:1999)这是在Github第360期中,尽管要提到的是,在8位中没有实际的区别—在线程360的末端附近,我有错误图表,包括8位中的0.04045 / 0.03928。
Myndex

8

添加其他所有人说的话:

所有这些方程式在实践中都可以很好地工作,但是如果您需要非常精确,则必须先将颜色转换为线性颜色空间(应用逆像-gamma),然后对原色进行加权平均,以及-如果要显示颜色-将亮度带回监视器伽玛。

在深灰色中,无法确定伽玛值和进行适当伽玛值之间的亮度差异高达20%。


2

我今天正在用JavaScript解决类似的任务。我已经getPerceivedLightness(rgb)为HEX RGB颜色确定了此功能。它通过Fairchild和Perrotta公式处理Helmholtz-Kohlrausch效应,以进行亮度校正。

/**
 * Converts RGB color to CIE 1931 XYZ color space.
 * https://www.image-engineering.de/library/technotes/958-how-to-convert-between-srgb-and-ciexyz
 * @param  {string} hex
 * @return {number[]}
 */
export function rgbToXyz(hex) {
    const [r, g, b] = hexToRgb(hex).map(_ => _ / 255).map(sRGBtoLinearRGB)
    const X =  0.4124 * r + 0.3576 * g + 0.1805 * b
    const Y =  0.2126 * r + 0.7152 * g + 0.0722 * b
    const Z =  0.0193 * r + 0.1192 * g + 0.9505 * b
    // For some reason, X, Y and Z are multiplied by 100.
    return [X, Y, Z].map(_ => _ * 100)
}

/**
 * Undoes gamma-correction from an RGB-encoded color.
 * https://en.wikipedia.org/wiki/SRGB#Specification_of_the_transformation
 * /programming/596216/formula-to-determine-brightness-of-rgb-color
 * @param  {number}
 * @return {number}
 */
function sRGBtoLinearRGB(color) {
    // Send this function a decimal sRGB gamma encoded color value
    // between 0.0 and 1.0, and it returns a linearized value.
    if (color <= 0.04045) {
        return color / 12.92
    } else {
        return Math.pow((color + 0.055) / 1.055, 2.4)
    }
}

/**
 * Converts hex color to RGB.
 * /programming/5623838/rgb-to-hex-and-hex-to-rgb
 * @param  {string} hex
 * @return {number[]} [rgb]
 */
function hexToRgb(hex) {
    const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
    if (match) {
        match.shift()
        return match.map(_ => parseInt(_, 16))
    }
}

/**
 * Converts CIE 1931 XYZ colors to CIE L*a*b*.
 * The conversion formula comes from <http://www.easyrgb.com/en/math.php>.
 * https://github.com/cangoektas/xyz-to-lab/blob/master/src/index.js
 * @param   {number[]} color The CIE 1931 XYZ color to convert which refers to
 *                           the D65/2° standard illuminant.
 * @returns {number[]}       The color in the CIE L*a*b* color space.
 */
// X, Y, Z of a "D65" light source.
// "D65" is a standard 6500K Daylight light source.
// https://en.wikipedia.org/wiki/Illuminant_D65
const D65 = [95.047, 100, 108.883]
export function xyzToLab([x, y, z]) {
  [x, y, z] = [x, y, z].map((v, i) => {
    v = v / D65[i]
    return v > 0.008856 ? Math.pow(v, 1 / 3) : v * 7.787 + 16 / 116
  })
  const l = 116 * y - 16
  const a = 500 * (x - y)
  const b = 200 * (y - z)
  return [l, a, b]
}

/**
 * Converts Lab color space to Luminance-Chroma-Hue color space.
 * http://www.brucelindbloom.com/index.html?Eqn_Lab_to_LCH.html
 * @param  {number[]}
 * @return {number[]}
 */
export function labToLch([l, a, b]) {
    const c = Math.sqrt(a * a + b * b)
    const h = abToHue(a, b)
    return [l, c, h]
}

/**
 * Converts a and b of Lab color space to Hue of LCH color space.
 * /programming/53733379/conversion-of-cielab-to-cielchab-not-yielding-correct-result
 * @param  {number} a
 * @param  {number} b
 * @return {number}
 */
function abToHue(a, b) {
    if (a >= 0 && b === 0) {
        return 0
    }
    if (a < 0 && b === 0) {
        return 180
    }
    if (a === 0 && b > 0) {
        return 90
    }
    if (a === 0 && b < 0) {
        return 270
    }
    let xBias
    if (a > 0 && b > 0) {
        xBias = 0
    } else if (a < 0) {
        xBias = 180
    } else if (a > 0 && b < 0) {
        xBias = 360
    }
    return radiansToDegrees(Math.atan(b / a)) + xBias
}

function radiansToDegrees(radians) {
    return radians * (180 / Math.PI)
}

function degreesToRadians(degrees) {
    return degrees * Math.PI / 180
}

/**
 * Saturated colors appear brighter to human eye.
 * That's called Helmholtz-Kohlrausch effect.
 * Fairchild and Pirrotta came up with a formula to
 * calculate a correction for that effect.
 * "Color Quality of Semiconductor and Conventional Light Sources":
 * https://books.google.ru/books?id=ptDJDQAAQBAJ&pg=PA45&lpg=PA45&dq=fairchild+pirrotta+correction&source=bl&ots=7gXR2MGJs7&sig=ACfU3U3uIHo0ZUdZB_Cz9F9NldKzBix0oQ&hl=ru&sa=X&ved=2ahUKEwi47LGivOvmAhUHEpoKHU_ICkIQ6AEwAXoECAkQAQ#v=onepage&q=fairchild%20pirrotta%20correction&f=false
 * @return {number}
 */
function getLightnessUsingFairchildPirrottaCorrection([l, c, h]) {
    const l_ = 2.5 - 0.025 * l
    const g = 0.116 * Math.abs(Math.sin(degreesToRadians((h - 90) / 2))) + 0.085
    return l + l_ * g * c
}

export function getPerceivedLightness(hex) {
    return getLightnessUsingFairchildPirrottaCorrection(labToLch(xyzToLab(rgbToXyz(hex))))
}

1

HSV色彩空间应该可以解决问题,具体取决于您所使用的语言,请参阅Wikipedia文章,您可能会获得库转换。

H是色相,它是颜色的数值(即红色,绿色...)

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

V是颜色的“亮度”。


7
HSV颜色空间的问题在于,对于蓝色黄色,您可以具有相同的饱和度和值,但是具有不同的色相。黄色是多少比蓝色更亮。HSL也是如此。
伊恩·博伊德

hsv从技术角度为您提供颜色的“亮度”。在感知亮度中,hsv确实失败了
user151496 2014年

HSV和HSL在感知上并不准确(甚至不接近)。它们可用于“控件”以调整相对颜色,但不能准确预测感知亮度。使用CIELAB的L *可获得感知的亮度。
Myndex

1

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

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

如果您要寻找颜色与白色的接近程度,可以使用(255,255,255)的欧式距离

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


1

Jive Dadson的反伽马公式在用Javascript实现时需要删除半调整,即函数gam_sRGB的返回必须返回int(v * 255); 不返回int(v * 255 + .5); 半调整会四舍五入,这可能导致R = G = B(即灰色三合会)上的值太高。R = G = B三元组上的灰度转换应产生等于R的值;这是该公式有效的证明。有关有效的公式,请参见九个灰度阴影(不需半调整)。


听起来您很了解自己,所以我删除了+0.5
Jive Dadson

我做了实验。在C ++中,它需要+0.5,因此我将其放回去。我添加了有关翻译成其他语言的注释。
吉夫·达德森

1

我不知道如何确定这些rgb系数。我自己做了一个实验,结果如下:

Y = 0.267 R + 0.642 G + 0.091 B

与长期建立的国际电联系数相近,但明显不同。我想知道对于每个观察者来说,这些系数是否可能不同,因为我们所有人眼中视网膜上的视锥和视杆数量可能不同,尤其是不同类型视锥之间的比率可能有所不同。

以供参考:

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的显示器,但对我来说都一样。而且,我的眼中国际电联系数从字面上看是错误的。

是的,我大概有正常的色觉。


在您的实验中,您是否先进行了线性化处理以去除gamma分量?如果您不这样做,则可以解释您的结果。但是,系数与CIE 1931实验相关,并且这些系数是17位观察者的平均值,因此是的,结果存在个体差异。
Myndex

1

这是一些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
}

0

请定义亮度。如果您要寻找颜色与白色的接近程度,可以使用(255,255,255)的欧式距离


1
不,您不能在sRGB值之间使用欧几里得距离,sRGB并不是感知上统一的笛卡尔/矢量空间。如果要使用欧几里得距离来衡量色差,则至少需要转换为CIELAB,或者更好的是,使用CAM之类的CIECAM02。
Myndex

0

HSV的“ V”可能正是您要寻找的。MATLAB具有rgb2hsv函数,前面引用的Wikipedia文章中充满了伪代码。如果RGB2HSV转换不可行,则精度较低的模型将是图像的灰度版本。


0

此链接深入介绍了所有内容,包括为何在R,G和B值之前存在那些乘数常量。

编辑:这里也有答案之一的解释(0.299 * R + 0.587 * G + 0.114 * B)


0

为了确定具有R的颜色的亮度,我将RGB系统颜色转换为HSV系统颜色。

在我的脚本中,出于其他原因,我之前使用了HEX系统代码,但是您也可以使用来使用RGB系统代码rgb2hsv {grDevices}。文档在这里

这是我的代码的这一部分:

 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

0

为了清楚起见,使用平方根的公式必须为

sqrt(coefficient * (colour_value^2))

sqrt((coefficient * colour_value))^2

证明在于将R = G = B三元组转换为灰度R。只有在对颜色值求平方而不是对颜色值乘以系数时才是正确的。参见九个灰度阴影


5
有括号不
匹配

除非您使用的系数是正确系数的平方根。
RufusVS
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.