详解RGB和XYZ色彩空间转换之上篇

前言

        首先需要指明本文中描述的R,G,B并非通常的sRGB中的三个分量R',G',B',而是波长分别为700nm,546.1nm,435.8nm的单色红光,单色绿光,单色蓝光。sRGB中的R'G'B'中的红色、绿色、蓝色已经不是单色光了。虽然习惯上大家都叫RGB,但是需要有所区别。本文将分别从为什么需要这种转换,怎么进行这种转换进行阐述。

为什么需要XYZ色彩空间?

        为什么需要从RGB映射到XYZ色彩空间,一句话表述就是因为方便计算。这样回答似乎太过简单,但是事实确实如此,详细原因需要回顾一下混色的原理。

1,色匹配实验

        C=r(R)+g(G)+b(B)

        上式中的加号表达的是组合之意,而非数学上的相加。式子右侧部分RGB是三种单色刺激色,rgb表示的是相对系数。

        \lambda_R=700

        \lambda_G=546.1

        \lambda_B=435.8

 对于可见光依次测量各个波长的三色刺激值,那么可以得到如下:

         C_1=r_1(R)+g_1(G)+b_1(B)

         C_2=r_2(R)+g_2(G)+b_2(B)

         C_3=r_3(R)+g_3(G)+b_3(B)

         C_4=r_4(R)+g_4(G)+b_4(B)

         C_i=r_i(R)+g_i(G)+b_i(B)

特别的当波长处于三基色波长时有如下:

        

波长(nm)rgb
700100
546.1010
435.8001

将所录的数据使用图形表达出来,可以看到部分波长期间,R分量出现了负值:

 代码如下:        

wave=csvread('./cie data/cie_rgb_5nm.csv',0,0,[0,0,68,0]);
R=csvread('./cie data/cie_rgb_5nm.csv',0,1,[0,1,68,1]);
G=csvread('./cie data/cie_rgb_5nm.csv',0,2,[0,2,68,2]);
B=csvread('./cie data/cie_rgb_5nm.csv',0,3,[0,3,68,3]);
r=R./(R+G+B);
g=G./(R+G+B);
b=B./(R+G+B);
figure
plot(wave,r,'r');hold on
plot(wave,g,'g');hold on
plot(wave,b,'b');hold on
legend('r','g','b','Location','east');

2,混色原理

更一般的表达,应该在式子的左右乘以功率系数:

    C_iP(i)=r_i(R)P_r(i)+g_i(G)P_g(i)+b_i(B)P_b(i)

其中功率有如下关系:

        P(i)=P_r(i)+P_g(i)+P_b(i)

实际做实验的过程中,保持功率不变,所以:

        P(1)=P(2)=P(3)=P(i)

假定现在有一束连续的光,连续的意思代表是光谱连续分布,设连续光的功率分布如下:

        P(\lambda),\lambda\in (380,780)

那么相对于色匹配实验的功率之比为:

        S(\lambda_i)=P(\lambda_i)/P(i)

因此这束光的颜色可以用下面的表达式描述:

        C=\int {S(\lambda)C(i)}d\lambda

       C_r=\int {S(\lambda_r)R(i)}d\lambda

        C_g=\int {S(\lambda_g)G(i)}d\lambda

        C_b=\int {S(\lambda_b)B(i)}d\lambda

 简单起见,如果这束光是离散的2个频点,那么就用求和的形式表达:

        C_r=S(\lambda_{r1})R(i_1)+S(\lambda_{r2})R(i_2)     

        C_g=S(\lambda_{g1})G(i_1)+S(\lambda_{g2})G(i_2)

        C_b=S(\lambda_{b1})B(i_1)+S(\lambda_{b2})B(i_2)

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是程序代码: ``` #include <stdio.h> #include <math.h> // 定义RGB颜色结构体 typedef struct { int r; // 红色分量 int g; // 绿色分量 int b; // 蓝色分量 } RGB; // 定义XYZ颜色结构体 typedef struct { double x; double y; double z; } XYZ; // 定义LAB颜色结构体 typedef struct { double l; double a; double b; } LAB; // RGBXYZ函数 XYZ rgb2xyz(RGB rgb) { double r = rgb.r / 255.0; double g = rgb.g / 255.0; double b = rgb.b / 255.0; if (r > 0.04045) { r = pow(((r + 0.055) / 1.055), 2.4); } else { r = r / 12.92; } if (g > 0.04045) { g = pow(((g + 0.055) / 1.055), 2.4); } else { g = g / 12.92; } if (b > 0.04045) { b = pow(((b + 0.055) / 1.055), 2.4); } else { b = b / 12.92; } r = r * 100.0; g = g * 100.0; b = b * 100.0; XYZ xyz; xyz.x = r * 0.4124 + g * 0.3576 + b * 0.1805; xyz.y = r * 0.2126 + g * 0.7152 + b * 0.0722; xyz.z = r * 0.0193 + g * 0.1192 + b * 0.9505; return xyz; } // XYZ转LAB函数 LAB xyz2lab(XYZ xyz) { double x = xyz.x / 95.047; double y = xyz.y / 100.0; double z = xyz.z / 108.883; if (x > 0.008856) { x = pow(x, 1.0 / 3.0); } else { x = (7.787 * x) + (16.0 / 116.0); } if (y > 0.008856) { y = pow(y, 1.0 / 3.0); } else { y = (7.787 * y) + (16.0 / 116.0); } if (z > 0.008856) { z = pow(z, 1.0 / 3.0); } else { z = (7.787 * z) + (16.0 / 116.0); } LAB lab; lab.l = (116.0 * y) - 16.0; lab.a = 500.0 * (x - y); lab.b = 200.0 * (y - z); return lab; } int main() { RGB rgb = {255, 255, 255}; // 定义RGB颜色 XYZ xyz = rgb2xyz(rgb); // RGBXYZ LAB lab = xyz2lab(xyz); // XYZ转LAB printf("RGB: (%d, %d, %d)\n", rgb.r, rgb.g, rgb.b); printf("XYZ: (%lf, %lf, %lf)\n", xyz.x, xyz.y, xyz.z); printf("LAB: (%lf, %lf, %lf)\n", lab.l, lab.a, lab.b); return 0; } ``` 注意:此程序只是实现了RGBXYZ再到LAB的转换,如果要实现其他色彩空间转换,需要修改相应的转换函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值