将RGB转换为灰度/强度


128

从RGB转换为灰度时,据说应该对通道R,G和B应用特定的权重。这些权重是:0.2989、0.5870、0.1140。

据说其原因是人类对这三种颜色的感知/敏感性不同。有时也有人说这些是用于计算NTSC信号的值。

但是,我在网上找不到很好的参考资料。这些值的来源是什么?

另请参阅以下先前的问题:在这里这里


26
是的,它确实。我一直在对RGB值进行编程。如果您希望自己的应用程序物有所值,那么将“真实世界”值应用于这些计算就非常重要。
尼尔N

1
许多程序员可能不在乎并计算“错误的”灰度图片,但我愿意。
ypnos

6
我同意它与编码有关-如果您正在编码图形,无疑会是一个有趣且相关的问题。+1,因为我想自己知道答案
Cruachan

6
RGB 编程有关。它与编程有关,与解析日期字符串有关。将文本“ true”转换为布尔值时。
尼尔N

Answers:


87

问题中的具体编号来自CCIR 601(请参见下面的Wikipedia链接)。

如果您使用稍有不同的数字/不同的方法转换RGB->灰度,则在正常照明条件下的普通计算机屏幕上根本看不到太大差异,请尝试一下。

一般而言,以下是一些有关颜色的链接:

维基百科亮度

布鲁斯·林德布洛姆Bruce Lindbloom)的出色网站

Colin Ware在书中第4章“颜色”,“信息可视化”,isbn 1-55860-819-2;在books.google.com中与Ware的长链接 可能有效,也可能无效

cambridgeincolor:出色的,写得很好的“关于如何使用强调过程概念的视觉导向方法来获取,解释和处理数码照片的教程”

如果您遇到的是“线性” RGB与“非线性” RGB,这是我对此的旧注释的一部分。重复一遍,在实践中您不会发现太大的区别。


RGB-> ^ gamma-> Y-> L *

在色彩科学中,常见的RGB值(如html rgb(10%,20%,30%))称为“非线性”或经过 Gamma校正的。“线性”值定义为

Rlin = R^gamma,  Glin = G^gamma,  Blin = B^gamma

其中,对于许多PC,伽玛为2.2。通常的RGB有时写为R'G'B'(R'= Rlin ^(1 / gamma))(纯粹单击舌头),但在这里我将删除'。

CRT显示器上的亮度与RGBlin = RGB ^ gamma成正比,因此CRT上50%的灰度非常暗:.5 ^ 2.2 =最大亮度的22%。(LCD显示更为复杂;此外,某些图形卡可补偿伽玛。)

要获得L*从RGB 调用的亮度度量,首先将RGB除以255,然后计算

Y = .2126 * R^gamma + .7152 * G^gamma + .0722 * B^gamma

这是Y在XYZ颜色空间中;它是颜色“亮度”的量度。(实际公式并非完全是x ^ gamma,而是近似值;请坚持使用x ^ gamma作为第一遍。)

最后,

L* = 116 * Y ^ 1/3 - 16

“ ...渴望感知统一性,并且与人类对亮度的感知紧密匹配。” - 维基百科实验室色彩空间


8
Y = 0.2126 * R + 0.7152 * G + 0.0722 * B-Wikipedia(en.wikipedia.org/wiki/Grayscale
iamantony


9

这是c中的一些代码,可将rgb转换为灰度。用于rgb到灰度转换的实际权重是0.3R + 0.6G + 0.11B。这些重量绝对不重要,因此您可以使用它们。我使它们为0.25R + 0.5G + 0.25B。它会产生稍暗的图像。

注意:以下代码假定xRGB 32位像素格式

unsigned int *pntrBWImage=(unsigned int*)..data pointer..;  //assumes 4*width*height bytes with 32 bits i.e. 4 bytes per pixel
unsigned int fourBytes;
        unsigned char r,g,b;
        for (int index=0;index<width*height;index++)
        {
            fourBytes=pntrBWImage[index];//caches 4 bytes at a time
            r=(fourBytes>>16);
            g=(fourBytes>>8);
            b=fourBytes;

            I_Out[index] = (r >>2)+ (g>>1) + (b>>2); //This runs in 0.00065s on my pc and produces slightly darker results
            //I_Out[index]=((unsigned int)(r+g+b))/3;     //This runs in 0.0011s on my pc and produces a pure average
        }

2
0.3 0.6 0.11不加1。维基百科似乎建议0.30 0.59 0.11。
damix911

没错,但是它们不加1的唯一结果就是强度发生了很小的变化。所建议的方法0.25,0.5,0.25确实加了1,但是没有影响。这是一项优化,因此放弃一点点精度是一个合理的权衡。
twerdster '16

2
@twerdster两组系数都不正确。.3,.6,.11是旧的NTSC标准,而不是sRGB / Rec709(Web和大多数计算机使用的标准)。而您的0.25,0.5,0.25并不是一个合理的权衡-B仅是亮度的7%,而您错了347%。sRGB / r709的系数(线性化后):Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722 = Y这些光谱权重来自于人类光谱感知。为了方便和希望准确起见,您不能只是添加任何数量的数字。您需要线性化sRGB,然后应用正确的系数。
Myndex

如果您处于除法过于昂贵的情况,则使用带移位和加法的单乘的近似值为: 0.11111111 * ((G + (G<<1) + R) <<1) + B)。这等效于(2*R+6*G+B) / 9)0.222 R + 0.666 G + 0.111 B。在开始生产之前,请比较各种测试用例的准确公式。
制造商史蒂夫(Steve)


6

请查看颜色常见问题解答以获取有关此信息。这些值来自我们在显示器中使用的RGB值的标准化。实际上,根据色彩常见问题解答,您使用的值已过时,因为它们是原始NTSC标准而不是现代显示器使用的值。


3

这些值的来源是什么?

张贴系数的“来源”是NTSC规范,可以在Rec601电视特性中看到。

“最终来源”是大约1931年的CIE关于人类色彩感知的实验。人类视觉的光谱响应不均匀。实验导致了基于感知的三刺激值的加权。我们的L,M和S锥1对分别标识为“三刺激”原色的“红色”,“绿色”和“蓝色”的光波长敏感。2

sRGB(和Rec709)的线性光3光谱权重为:

R lin * 0.2126 + G lin * 0.7152 + B lin * 0.0722 = Y

这些特定于sRGB和Rec709色彩空间,旨在代表计算机监视器(sRGB)或HDTV监视器(Rec709),并在ITU文档中针对Rec709BT.2380-2(10/2018)进行了详细说明。

脚注 (1)锥体是眼睛视网膜的颜色检测细胞。
(2)然而,所选的三刺激波长不在每个锥体类型的“峰值”处-而是选择三刺激值,以使它们对特定的锥体类型的刺激远大于另一种刺激类型,即刺激的分离。
(3)在应用系数之前,您需要线性化sRGB值。我在这里另一个答案中对此进行讨论



-4

这是真的必要L = (R + G + B)/3吗,人类的感知和CRT与LCD的关系会有所不同,但是RGB强度没有变化,为什么不将新的RGB设置为L,L,L?


3
简单地对所有三个R,G,B基元求平均,就可以将它们视为在感知上相等,而对于人类视觉系统而言,情况并非如此。
比尔·菲斯
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.