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);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章