将 RGB 转换为灰度/强度

Posted

技术标签:

【中文标题】将 RGB 转换为灰度/强度【英文标题】:Converting RGB to grayscale/intensity 【发布时间】:2010-10-15 19:03:59 【问题描述】:

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

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

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

另请参阅之前的这些问题:here 和 here。

【问题讨论】:

是的。我一直在对 RGB 值进行编程。如果您希望您的应用物有所值,那么将“真实世界”值应用于这些计算非常重要。 许多程序员可能不关心和计算“错误”的灰度图片,但我关心。 我同意它与编码相关 - 如果您正在编码图形,这无疑是一个有趣且相关的问题。 +1,因为我想自己知道答案 RGB 编程相关的。它与解析日期字符串一样与编程相关。将文本“true”转换为布尔值。 @pnizzle poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC9 【参考方案1】:

问题中的具体数字来自 CCIR 601(参见Wikipedia article)。

如果你用稍微不同的数字/不同的方法转换 RGB -> 灰度, 在普通的电脑屏幕上你根本看不到太大的区别 在正常光照条件下——试试吧。

这里有更多关于颜色的链接:

***Luma

Bruce Lindbloom 的优秀网站

Colin Ware 所著的“信息可视化”一书中关于颜色的第 4 章,isbn 1-55860-819-2; 这个长链接到books.google.com中的Ware 可能有效也可能无效

cambridgeincolor : 很好,写得很好 “关于如何获取、解释和处理数码照片的教程 使用以视觉为导向的方法,强调概念而非过程"

如果您遇到“线性”与“非线性”RGB, 这是对我自己的旧笔记的一部分。 重复一遍,在实践中你不会看到太大的不同。


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

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

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

对于许多 PC,gamma 为 2.2。 通常的 R G B 有时写为 R' G' B' (R' = Rlin ^ (1/gamma)) (纯粹主义者的舌头点击)但在这里我会放弃'。

CRT 显示器的亮度与 RGBlin = RGB ^ gamma 成正比, 所以 CRT 上 50% 的灰色非常暗:0.5 ^ 2.2 = 最大亮度的 22%。 (液晶显示器更复杂; 此外,一些显卡会补偿 gamma。)

要从 RGB 中获取名为 L* 的亮度度量, 先将 R G B 除以 255,然后计算

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

这是 XYZ 颜色空间中的Y;它是颜色“亮度”的量度。 (真正的公式并不完全是 x^gamma,而是接近; 坚持使用 x^gamma 进行第一遍。)

最后,

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

“...渴望感知一致性 [和] 与人类对亮度的感知非常接近。” -- ***Lab color space

【讨论】:

Y = 0.2126 * R + 0.7152 * G + 0.0722 * B - *** (en.wikipedia.org/wiki/Grayscale) 您好,我可以通过将 RGB 彩色图像显示为灰度图像来获得等效的全色图像吗?或者从RGB转换成HIS格式图像的强度分量能否代表全色图像? @emberbillow,有 许多 种将颜色映射到灰度的方法,其中一些可能在某些时候效果很好。你在用什么程序,你读过它的文档吗?您可以在几张您的测试图像上试一试。 谢谢你,丹尼斯。我没有使用软件。当我阅读全色图像的定义时,我才想到这个问题。众所周知,全色图像上像素的亮度大致代表了地表的反射能力。因此,由于 RGB 彩色图像大约覆盖了可见光的波段间隔,我猜它的灰度格式可以代表全色图像。我不确定我的理解是否正确。 @enberbillow,*** 是针对软件和编程问题的,最好是an example。试试 google RGB IHS 全色灰度?【参考方案2】:

我发现此出版物在对先前类似问题的回答中被引用。很有帮助,页面有几个示例图片:

Perceptual Evaluation of Color-to-Grayscale Image Conversions Martin Čadík,计算机图形学论坛,2008 年第 27 卷

该出版物探讨了其他几种生成具有不同结果的灰度图像的方法:

CIE Y Color2Gray 脱色 史密斯08 Rasche05 巴拉04 纽曼07

有趣的是,它得出的结论是,没有普遍最佳的转换方法,因为每种方法的表现都比其他方法更好或更差,具体取决于输入。

【讨论】:

@JackDeeth 我不知道如何总结链接的网站,因为它都是关于视觉比较的。 你说得对,我不应该投这样的票。对不起!【参考方案3】:

这是 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
        

【讨论】:

0.3 0.6 0.11 不要加到 1。***似乎建议 0.30 0.59 0.11。 是的,但它们不加 1 的唯一结果是强度会发生非常轻微的变化。建议的 0.25,0.5,0.25 方法确实加到 1,但如果不加也没有关系。这是一种优化,因此放弃一点点准确性是一个合理的权衡。 @twerdster 两组系数都不正确。 .3,.6,.11 是旧的 NTSC 标准,而不是 sRGB/Rec709(这是网络和大多数计算机使用的)。而你的 0.25,0.5,0.25 并不是一个合理的权衡——B 只是亮度的 7%,你错了 347%。 sRGB/r709 的系数(线性化后):Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722 = Y 这些光谱权重源自人类光谱感知。您不能为了方便而随意输入任何数字,并希望准确无误。您需要对 sRGB 进行线性化,然后应用正确的系数。 如果您处于除法过于昂贵的情况下,使用单次乘法和移位和加法的近似值是:0.11111111 * ((G + (G&lt;&lt;1) + R) &lt;&lt;1) + B)。这相当于(2*R+6*G+B) / 9)0.222 R + 0.666 G + 0.111 B。在投入生产之前,与各种测试用例的准确公式进行比较。【参考方案4】:

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

【讨论】:

【参考方案5】:

这些值的来源是什么?

发布的系数的“来源”是 NTSC 规范,可以在 Rec601 和 Characteristics of Television 中看到。

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

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

Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722 = Y

这些特定于 sRGB 和 Rec709 色彩空间,旨在表示计算机显示器 (sRGB) 或 HDTV 显示器 (Rec709),并在 Rec709 和 BT.2380-2 (10/2018) 的 ITU 文档中进行了详细说明

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

【讨论】:

【参考方案6】:

开始一个列表来列举不同的软件包是如何做到的。 Here is a good CVPR paper to read as well.

FreeImage

#define LUMA_REC709(r, g, b)    (0.2126F * r + 0.7152F * g + 0.0722F * b)
#define GREY(r, g, b) (BYTE)(LUMA_REC709(r, g, b) + 0.5F)

OpenCV

nVidia Performance Primitives

Intel Performance Primitives

Matlab

nGray =  0.299F * R + 0.587F * G + 0.114F * B; 

【讨论】:

【参考方案7】:

这些价​​值观因人而异,尤其是对于色盲的人。

【讨论】:

【参考方案8】:

这一切真的有必要吗,人类的感知和 CRT vs LCD 会有所不同,但 R G B 强度不会,为什么不L = (R + G + B)/3 并将新的 RGB 设置为 L、L、L?

【讨论】:

简单地对所有三个 R、G、B 原色进行平均就可以将它们视为感知上的平等,而人类视觉系统并非如此。

以上是关于将 RGB 转换为灰度/强度的主要内容,如果未能解决你的问题,请参考以下文章

将 Rgb 图像转换为灰度 C# 代码时的性能问题

Python如何将RGB图像转换为Pytho灰度图像?

将灰度图像转换为 rgb 图像并在 matlab 中将其替换为 imread()

如何将 RGB 图像转换为灰度但保留一种颜色? - 爪哇

将位图(RGB_565)转换为灰度(8位)Android

在 ImageMagick 命令行中将 RGB 转换为灰度