CV(1) : 光 颜色 颜色空间

1 光

  视觉系统要从光开始说起。光作为电磁波在空间中传播,也是一种粒子流(光子)。

图1 电磁波光谱

可见光区大致为 380 ~ 740 nm.

2 人眼

眼睛主要有2种感光细胞:

  • cone cells:视锥细胞。细节,色彩视觉,需要很多光子激活,亮光。集中在视网膜中心位置。
  • rod cells:视杆细胞。低光,单色视觉。分散在视网膜两外边。
图 2 人眼简单结构

3 颜色

3.1 感知亮度

波长不同,感知的亮度也是不同的。感知亮度和波长曲线如下图:

图3 感知亮度波长曲线
  绿色蓝色亮度高很多,所以一般黑色背景下人们更容易看清绿色,而不是蓝色,比如安全出口警示牌则一般为绿色,以更容易引起人们注意。
This is hard to see
This is easy to see

3.2 三原色

每个感光细胞都有一个响应曲线,对不同波长光反应有所不同:

  • 视杆细胞:峰值在498nm附近。
  • 视锥细胞:3种,短的峰值在420nm附近,中等的峰值在530nm附近,长的峰值在560nm附近。
图 4 感光细胞的波长反应光谱
  色彩的感知来自视锥细胞,是我们对波的感知。

  1920s年代末期,William Wright 和 John Guild等认为三种视锥细胞的感知峰值分别在蓝色,绿色,红色上(现在技术已经证明这一结论并不是完全准确,但对他们得出的结论并不影响),通过实验发现控制3中“基本光”可以获得所有的颜色。

图 5 RGB颜色匹配曲线
即三原色:R, G, B.
图 6 三原色

4 颜色空间

  颜色空间用来表示尽可能多的视觉系统可以感知的颜色,不同的颜色空间可以表示的颜色范围可能是不同的。

4.1 XYZ color space

   XYZ color space是根据人类视觉系统对颜色的响应而做的,即视锥细胞对可见光谱的响应。CIE通过大量实验获得了CIE标准观察颜色匹配函数

在这里插入图片描述

图 7 XYZ颜色匹配曲线

可以用以下公式将光谱转化为X, Y, Z 三个值:
X=1Y(λ)dλλSe(λ)Xˉ(λ)dλY=1Y(λ)dλλSe(λ)Yˉ(λ)dλZ=1Y(λ)dλλSe(λ)Zˉ(λ)dλ \begin{array}{l} X={\dfrac{1}{\int Y(\lambda)d \lambda}} \int_\lambda S_e(\lambda) \bar{X}(\lambda) d \lambda \\ Y={\dfrac{1}{\int Y(\lambda)d \lambda}} \int_\lambda S_e(\lambda) \bar{Y}(\lambda) d \lambda \\ Z={\dfrac{1}{\int Y(\lambda)d \lambda}} \int_\lambda S_e(\lambda) \bar{Z}(\lambda) d \lambda \\ \end{array}
其中Se(λ)S_e(\lambda) 代表光谱强度。

图 8 XYZ空间色域

4.2 rgb color space

  图5展示了rgb的颜色匹配函数,其中在438.1~546.1nm之间R值出现了负值,这说明有一部分颜色是rgb空间不能包含的。

图 9 RGB颜色空间
  • XYZ \rightarrow RGB

[RGB]=[2.37067430.90004050.47063380.51388501.42530360.08858140.00529820.01469491.0093968][XYZ] \begin{bmatrix} R \\ G \\ B \\ \end{bmatrix} = \begin{bmatrix} 2.3706743 & -0.9000405 & -0.4706338 \\ -0.5138850 & 1.4253036 & 0.0885814 \\ 0.0052982 & -0.0146949 & 1.0093968 \\ \end{bmatrix} \begin{bmatrix} X \\ Y \\ Z \\ \end{bmatrix}

4.3 Hue color space

  • Hue: 色调,从红色开始按逆时针方向计算,红色为0. 范围取[0,1)
  • Saturation: 饱和度,表示颜色接近光谱色的程度。
  • Value:明度,表示颜色明亮的程度。
图 10 HSV 颜色空间

  将红,黄,绿,青,蓝,品红6种颜色均匀放在一条轴上,再采用线性插值的办法得到色调。

在这里插入图片描述

图 11 Hue展开图

  • RGB \rightarrow HSV

V=max(R,G,B)m=min(R,G,B)delta=VmS=delta/V {\color{Red}V} = max(R, G, B) \\ m = min(R, G, B) \\ delta = V - m \\ {\color{Red}S} = delta / V
H={0,delta=0GBdelta,V=RBRdelta+2,V=GRGdelta+4,V=B {\color{Red}H} = \begin{cases} 0, & delta=0 \\ \tfrac{G - B}{delta}, & V = R \\ \tfrac{B - R}{delta} + 2, & V = G \\ \tfrac{R - G}{delta} + 4, & V = B \end{cases}
H={H6+1,ifH<0H6,otherwise {\color{Red}H} = \begin{cases} \tfrac{H}{6} + 1, & if H < 0 \\ \tfrac{H}{6}, & otherwise \end{cases}
参考C代码:
定义简单的image结构体:

typedef struct{
    int w,h,c;
    float *data;
} image;

色彩空间转换函数:

void rgb_to_hsv(image im)
{
    assert(im.c == 3);
    int i, j;
    float r, g, b;
    float h, s, v;
    for(j = 0; j < im.h; j++) {
        for(i = 0; i < im.w; i++) {
            r = get_pixel(im, i, j, 0);
            g = get_pixel(im, i, j, 1);
            b = get_pixel(im, i, j, 2);

            float maxVal = three_way_max(r, g, b);
            float minVal = three_way_min(r, g, b);

            float delta = maxVal - minVal;

            // compute Value
            v = maxVal;

            // compute Saturation and Hue
            if(maxVal == 0) {
                s = 0;
                h = 0;
            } else {
                s = delta / maxVal;
                if(delta == 0) {
                    h = 0;
                } else if(v == r) {
                    h = (g - b) / delta;
                } else if (v == g) {
                    h = (b - r) / delta + 2;
                } else if (v == b) {
                    h = (r - g) / delta + 4;
                }

                if(h < 0) h += 6;
                h /= 6;
            }

            set_pixel(im, i, j, 0, h);
            set_pixel(im, i, j, 1, s);
            set_pixel(im, i, j, 2, v);
        }
    }
}
  • HSV \rightarrow RGB
    H=6HH = 6 * H
    max=Vmax = V
    min=V(1S)min = V * (1 - S)
    delta=VSdelta = V * S
    deltaH=HHdeltaH = H - \left \lfloor H \right \rfloor
    p=min+deltadeltaHp = min + delta * deltaH
    q=min+delta(1deltaH)q = min + delta * (1 - deltaH)

{R=max,B=min,G=p,0H<1G=max,B=min,R=q,1H<2G=max,R=min,B=p,2H<3B=max,R=min,G=q,3H<4B=max,G=min,R=p,4H<5R=max,G=min,B=q,5H<6 \begin{cases} {\color{Red}R} = max, {\color{Red}B} = min, {\color{Red}G} = p, & 0 \leq H < 1 \\ {\color{Red}G} = max, {\color{Red}B} = min, {\color{Red}R} = q, &1 \leq H < 2 \\ {\color{Red}G} = max, {\color{Red}R} = min, {\color{Red}B} = p, & 2 \leq H < 3 \\ {\color{Red}B} = max, {\color{Red}R} = min, {\color{Red}G} = q, &3 \leq H < 4 \\ {\color{Red}B} = max, {\color{Red}G} = min, {\color{Red}R} = p, & 4 \leq H < 5 \\ {\color{Red}R} = max, {\color{Red}G} = min, {\color{Red}B} = q, &5 \leq H < 6 \\ \end{cases}
参考C代码:

void hsv_to_rgb(image im)
{
    assert(im.c == 3);
    int i, j;
    float h, s, v;
    float r, g, b;
    for(j = 0; j < im.h; j++) {
        for(i = 0; i < im.w; i++) {
            h = 6 * get_pixel(im, i, j, 0);
            s = get_pixel(im, i, j, 1);
            v = get_pixel(im, i, j, 2);
            
            float maxVal = v;
            float minVal = v * (1 - s);
            float delta = v * s;

            int hInt = floor(h);
            // float deltaH = h - hInt;
            // float p = minVal + delta * deltaH;
            // float q = minVal + delta * (1 - deltaH);
            float val = minVal + delta * (1 - fabs(fmod(h, 2) - 1));

            switch(hInt) {
                case 0:
                    r = maxVal; b = minVal; g = val; break; // g = p;
                case 1:
                    g = maxVal; b = minVal; r = val; break; // r = q;
                case 2:
                    g = maxVal; r = minVal; b = val; break; // b = p;
                case 3:
                    b = maxVal; r = minVal; g = val; break; // g = q;
                case 4:
                    b = maxVal; g = minVal; r = val; break; // r = p;
                default:
                    r = maxVal; g = minVal; b = val;        // b = q;
            }
            set_pixel(im, i, j, 0, r);
            set_pixel(im, i, j, 1, g);
            set_pixel(im, i, j, 2, b);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章