(原创)[短小精悍系列]RGB(RGI/RGV)颜色亮度计算公式 (又称灰度公式,彩色照片转黑白照片时能派上用场)

作者:❄️固态二氧化碳❄️ (主页)
链接:(原创)[短小精悍系列]RGB(RGI/RGV)颜色明度(亮度)计算公式 (又称灰度公式,彩色照片转黑白照片时能派上用场) - 固态二氧化碳的博客 - CSDN博客
来源:博客园
发表时间:2019年09月25日 10:37:23
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

先上公式:
\(L=k\sqrt[2.2]{(\frac{R}{255})^{2.2}+(1.5\frac{G}{255})^{2.2}+(0.6\frac{B}{255})^{2.2}}\)
其中\(k=\sqrt[2.2]{\frac{1}{1+1.5^{2.2}+0.6^{2.2}}}≈0.547373\)
L取值范围为\(0\sim1\),黑色\(L=0\),白色\(L=1\)

友情提示:现在网上大多数计算公式(诸如0.30R+0.59G+0.11B之类的)都是错的,因为它们连最基本的gamma校正都没考虑进去,结果自然会错得十分离谱。看到这类形式十分简单,只有加法和乘法,连根号都不带的公式,一律都是错的!

  目前绝大多数电脑,手机,平板,电视等电子设备使用sRGB色彩空间。观测表明,在大部分使用sRGB色彩空间的显示器上,红(R),绿(G),蓝(B)三原色的亮度(心理亮度)比为\(\color{#0080FF}1:1.5:0.6\),也就是说,RGB三分量数值为\(1:\frac{2}{3}:\frac{5}{3}\),即\(3:2:5\)时,亮度相等,对应的十六进制值分别为#990000,#006600,#0000FF(不同显示器显示效果可能会有偏差,也可能同一台显示器因为调整过色温而导致误差,但大概八九不离十,这里的比值是根据大量显示器显示效果统计得来的平均值)。换句话说,三原色在计算机中的值相等时(如均为255),其实际强度大小并非严格相等,而是存在一定的比例关系
  至于原因嘛,那就是三原色配比成白色的问题了,又叫白平衡。如果三原色亮度严格按照1:1:1配比,那么颜色就会明显偏冷,就像这样一个颜色:#DDCCFF,一种偏蓝紫色的颜色,这是因为我们对冷色光(高频光,蓝紫色光)太过于敏感,而对暖色光(低频光)敏感性则略逊一筹,这里所说的敏感指的是光对色度的影响,即混入一种光后对色度图上颜色坐标的影响程度。打个很简单的比方,红色和蓝色叠加得到的紫色更偏向于冷色(蓝色),而不是暖色(红色)。再比如,白色中缺少一点点红色的冰蓝色(#CCFFFF)和白色中缺少一点点蓝紫色的淡黄色(#FFFFCC),明显前者更接近白,后者则太黄,如果放在手机上面,两者就是所谓的"冷屏"和"暖屏",说得不好听一点,后者就是传说中的"shi黄屏"。
  所以为了避免这个问题,三原色的配比不能严格按照1:1:1,而是红绿色要比蓝紫色多,才能保证生成完美的白色,也就是不冷不暖的白色,因为人眼对于冷色太过于敏感。这也就导致了RGB(RGI/RGV)中三原色的亮度不一致,绿色亮度比较大,红色适中,而蓝紫色(靛色)则明显偏小。为了合成出真正的蓝色,我们需要在蓝色分量(B)中加入适量的绿色分量(G),这样既把原来偏紫的蓝变正宗了,而且亮度也变大了。所以在RGB(RGI/RGV),正宗的蓝色对应的色相为210°,而不是240°,这一点我在之前的文章已经说过了。
  最后一点,刚才我所说的"亮度"指的都是心理亮度,但是还有一种亮度,称为"物理亮度",这是怎么回事呢?原来,物理亮度由功率决定,与功率成正比,而人眼对亮度的感知与功率并不成正比,而是幂函数的关系,这个函数的指数我们通常称作伽马(gamma)值,符号为γ。如果我们把物理亮度记为\(L_p\),心理亮度记为\(L\),则有\(L_p=L^γ\),而大量研究表明,这个伽马值通常在1.8~2.6之间,在绝大多数发光设备上,这个值取的是2.2,所以我们有\(L_p=L^{2.2}\)而我们常说的RGI三分量的大小对应的是心理亮度,虽然有极少数用物理亮度表示,通常把前者称为Gamma(非线性)空间,后者称为线性空间。关于线性和非线性空间的知识,我会在以后的博文重点讲解的。
  而色光亮度的合成是遵循物理亮度(线性空间)的,并非心理亮度,而最后合成得到的亮度又要换算成心理亮度。而之前我们有,RGB三原色心理亮度比为\(1:1.5:0.6\),故物理亮度比为\(1:1.5^{2.2}:0.6^{2.2}\)。因此对于某种颜色的亮度(心理亮度),我们有

\[L^{2.2}=k^{2.2}[(\frac{R}{255})^{2.2}+(1.5\frac{G}{255})^{2.2}+(0.6\frac{B}{255})^{2.2}] \]

  规定白色的亮度为1,则\(1=k^{2.2}(1+1.5^{2.2}+0.6^{2.2})\)
  解得\(k=\sqrt[2.2]{\frac{1}{1+1.5^{2.2}+0.6^{2.2}}}≈0.547373\)
  将前面的长式子两边开2.2次方,得

\[L=k\sqrt[2.2]{(\frac{R}{255})^{2.2}+(1.5\frac{G}{255})^{2.2}+(0.6\frac{B}{255})^{2.2}} \]

  噫,大家发现了什么吗?如果把\(\frac{R}{255}\),\(1.5\frac{G}{255}\),\(0.6\frac{B}{255}\)看成一个整体,这公式和勾股定理长得贼像!只不过指数由2变成2.2(伽马值),外面还有个系数k没乘进去。而这三个整体,把根号外面的k乘进去后,反映的正是三个分量对应的亮度!看来,光的(心理)亮度的合成是遵循"勾股定理"的,只不过指数变成了2.2,我们姑且把它称之为"类勾股定理"吧!(其实,在数学上,这个玩意叫范数,通俗地说,指数为p的"勾股定理"对应的就是p-范数。比如说欧氏几何的勾股定理就是2-范数,而刚才所说的亮度的合成,就是2.2-范数)。利用这个定理,我们就可以解释为什么红色(\(L=k\))和绿色(\(L=1.5k\))合成的黄色的亮度并不是\(2.5k\),显著高于绿色,而是\(1.75345k\),与绿色亮度相差无几,类比勾股定理,你就可以很直观地去理解它了。
  在以后的文章中,我还会继续利用"勾股定理"这个思想去解决关于亮度的问题的。

  最后,附上算法代码(C语言)。共两个函数,lightness函数返回亮度值(0~1),rgb2gray函数返回灰度值(0~255)

#include <math.h>
typedef unsigned char uint8;

const float k=0.547373141f;

float lightness(uint8 R,uint8 G,uint8 B)
{
    return pow(pow(R/255.0f,2.2f)+pow(G/170.0f,2.2f)+pow(B/425.0f,2.2f),1/2.2f)*k;
}

uint8 rgb2gray(uint8 R,uint8 G,uint8 B)
{
    return (uint8)(pow(pow(R,2.2f)+pow(G*1.5f,2.2f)+pow(B*0.6f,2.2f),1/2.2f)*k);
}

  将彩色照片转换成黑白照片时,只需将每一个像素点的亮度值乘上255即可得到其等价灰度值,即黑白照片中RGB三个分量共同的值

posted @ 2020-02-19 21:47  固态二氧化碳  阅读(4542)  评论(0编辑  收藏  举报