1. 程式人生 > >RGB彩色空間的不同轉換公式

RGB彩色空間的不同轉換公式

在做影象處理時,我們一般採用的是RGB空間,但是在某些特殊情況下,我們也會用到其他的顏色空間。本文主要介紹一些常見的顏色空間的概念和轉換公式。

顏色的實質是一種光波。它的存在是因為有三個實體:光線、被觀察的物件以及觀察者。人眼是把顏色當作由被觀察物件吸收或者反射不同波長的光波形成的。例如,當在一個晴朗的日子裡,我們看到陽光下的某物體呈現紅色時,那是因為該物體吸收了其它波長的光,而把紅色波長的光反射到我們人眼裡的緣故。當然,我們人眼所能感受到的只是波長在可見光範圍內的光波訊號。當各種不同波長的光訊號一同進入我們的眼睛的某一點時,我們的視覺器官會將它們混合起來,作為一種顏色接受下來。同樣我們在對影象進行顏色處理時,也要進行顏色的混合,但我們要遵循一定的規則,即我們是在不同顏色模式下對顏色進行處理的。

1.RGB顏色模式

  雖然可見光的波長有一定的範圍,但我們在處理顏色時並不需要將每一種波長的顏色都單獨表示。因為自然界中所有的顏色都可以用紅、綠、藍(RGB)這三種顏色波長的不同強度組合而得,這就是人們常說的三基色原理。因此,這三種光常被人們稱為三基色或三原色。有時候我們亦稱這三種基色為新增色(Additive Colors),這是因為當我們把不同光的波長加到一起的時候,得到的將會是更加明亮的顏色。把三種基色互動重疊,就產生了次混合色:青(Cyan)、洋紅(Magenta)、黃(Yellow)。這同時也引出了互補色(Complement Colors)的概念。基色和次混合色是彼此的互補色,即彼此之間最不一樣的顏色。例如青色由藍色和綠色構成,而紅色是缺少的一種顏色,因此青色和紅色構成了彼此的互補色。在數字視訊中,對RGB三基色各進行8位編碼就構成了大約16.7萬種顏色,這就是我們常說的真彩色。順便提一句,電視機和計算機的監視器都是基於RGB顏色模式來建立其顏色的。

2.Lab顏色模式

  Lab顏色是由RGB三基色轉換而來的,它是由RGB模式轉換為HSB模式和CMYK模式的橋樑。該顏色模式由一個發光率(Luminance)和兩個顏色(a,b)軸組成。它由顏色軸所構成的平面上的環形線來表示顏色的變化,其中徑向表示色飽和度的變化,自內向外,飽和度逐漸增高;圓周方向表示色調的變化,每個圓周形成一個色環;而不同的發光率表示不同的亮度並對應不同環形顏色變化線。它是一種具有“獨立於裝置”的顏色模式,即不論使用任何一種監視器或者印表機,Lab的顏色不變。

RGB=>Lab

|X|   |0.433910  0.376220  0.189860| |R/255|
|Y| = |0.212649  0.715169  0.072182|*|G/255|
|Z|   |0.017756  0.109478  0.872915| |B/255|

L = 116*Y1/3
for Y>0.008856 L = 903.3*Y for Y<=0.008856 a = 500*(f(X)-f(Y)) b = 200*(f(Y)-f(Z)) 其中 f(t)=t1/3 for t>0.008856 f(t)=7.787*t+16/116 for t<=0.008856

3.HSB顏色模式

  從心理學的角度來看,顏色有三個要素:色澤(Hue)、飽和度(Saturation)和亮度(Brightness)。HSB顏色模式便是基於人對顏色的心理感受的一種顏色模式。它是由RGB三基色轉換為Lab模式,再在Lab模式的基礎上考慮了人對顏色的心理感受這一因素而轉換成的。因此這種顏色模式比較符合人的視覺感受,讓人覺得更加直觀一些。它可由底與底對接的兩個圓錐體立體模型來表示,其中軸向表示亮度,自上而下由白變黑;徑向表示色飽和度,自內向外逐漸變高;而圓周方向,則表示色調的變化,形成色環。

RGB=>HSB

V=max(R,G,B)
S=(V-min(R,G,B))*255/V   if V!=0, 0 otherwise

       (G - B)*60/S,  if V=R
H= 180+(B - R)*60/S,  if V=G
   240+(R - G)*60/S,  if V=B

若 H<0,則 H=H+360

使用上面從 0° 到 360° 變化的公式計算色調( hue)值,確保它們被 2 除後能試用於8位。

4.YUV顏色模式

  這是電視系統中常用的顏色模式,即電視中所謂的分量(Component)訊號。該模式由一個亮度訊號Y和兩個色差訊號U、V組成。它是利用了人眼對亮度訊號敏感而對色度訊號相對不敏感的特點,將RGB顏色通過亮度訊號公式Y=039R+050G+011B轉換為一個亮度訊號Y和兩個色差分量訊號U(R-Y)、V(B-Y),即對色差訊號進行了頻帶壓縮。毫無疑問,這是以犧牲訊號的質量為代價的。

RGB<=>YUV
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B

R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U

5.CMYK顏色模式

  這是彩色印刷使用的一種顏色模式。它由青(Cyan)、洋紅(Magenta)、黃(Yellow)和黑(Black)四種顏色組成。其中黑色之所以用K來表示,是為避免和RGB三基色中的藍色(Blue,用B表示)發生混淆。該種模式的建立基礎和RGB不同,它不是靠增加光線,而是靠減去光線,因為和監視器或者電視機不同的是,列印紙不能建立光源,它不會發射光線,只能吸收和反射光線。因此通過對上述四種顏色的組合,便可以產生可見光譜中的絕大部分顏色了。

RGB<=CMYK

   R = (255 - C) * ((255 - K) / 255)
    G = (255 - M) * ((255 - K) / 255)
    B = (255 - Y) * ((255 - K) / 255)


6.部分程式code

void HSI2RGB(BYTE &BR,BYTE &BG,BYTE &BB,BYTE BH,BYTE BS,BYTE BI)
{
 int nHValue = static_cast<int>(BH);
 int nSValue = static_cast<int>(BS);
 int nLValue = static_cast<int>(BI);

 float fHAngle = ((float)nHValue ) / 255 * 360;
 
 float H = fHAngle / 180 * PI;
 float S = ((float)nSValue ) / 100;
 float I = ((float)nLValue ) / 100;

 float R = -1;
 float G = -1;
 float B = -1;

 if(fHAngle >= 0 && fHAngle < 120)
 {
  B = I * ( 1.0 - S );
  R = I * ( 1.0 + ( S * cos( H ) / cos( 60.0 / 180 * PI - H ) ) );
  G = 3.0 * I - ( B + R );
 }
 else if(fHAngle >= 120 && fHAngle < 240)
 {
  R = I * ( 1.0 - S );
  G = I * ( 1.0 + S * cos( H - 120.0 / 180 * PI ) / cos( 180.0 / 180 * PI - H )  );
  B = 3.0 * I - ( R + G );
 }
 else if(fHAngle >= 240 && fHAngle < 360)
 {
  G = I * ( 1.0 - S );
  B = I * ( 1.0 + S * cos( H - 240.0 / 180 * PI ) / cos( 300.0 / 180 * PI - H ) );
  R = 3.0 * I - ( G + B );
 }
 int R_value_in_rgb = R * 255;
 int G_value_in_rgb = G * 255;
 int B_value_in_rgb = B * 255;
 BR = static_cast<BYTE>(R_value_in_rgb);
 BG = static_cast<BYTE>(G_value_in_rgb);
 BB = static_cast<BYTE>(B_value_in_rgb);
}

void  RGB2HSI(BYTE r,BYTE g,BYTE b,BYTE &h,BYTE &s,BYTE &i)
{
 short m_fr = static_cast<short>(r);
 short m_fg = static_cast<short>(g);
 short m_fb = static_cast<short>(b);

 float m_fiR = static_cast<float>(m_fr) / 255;
 float m_fsG = static_cast<float>(m_fg) / 255;
 float m_fhB = static_cast<float>(m_fb) / 255;
  
 if( m_fr == m_fg && m_fg == m_fb)
 {
  int iHValue = 0;
  int iSValue = 0;
  int iLValue = ((float)m_fr)/ 255 * 100;
  h = static_cast<BYTE>(iHValue);
  s = static_cast<BYTE>(iSValue);
  i = static_cast<BYTE>(iLValue);  
  return;
 }
 float max_value_of_rgb = GetMax( m_fiR, m_fsG, m_fhB );
 float min_value_of_rgb = GetMin( m_fiR, m_fsG, m_fhB );
 float fSumRGB =m_fiR + m_fsG + m_fhB ;
 if( fSumRGB <= 0.0 )
  fSumRGB = 0.001;
 float I = (m_fiR + m_fsG + m_fhB) / 3;
 float S = 1.0 - 3.0 * min_value_of_rgb / fSumRGB;
 float H = acos( (( m_fiR - m_fsG ) + ( m_fiR - m_fhB ))/2 / sqrt( ( m_fiR - m_fsG )*( m_fiR - m_fsG ) + ( m_fiR -m_fhB ) * ( m_fsG - m_fhB)  + 0.0001 ) );
 float fHAngle = H / PI * 180;
 if( m_fsG < m_fhB )
  fHAngle = 360 - fHAngle;
 if( fHAngle > 360.0 )
  fHAngle = 360.0;
 int nHValue = fHAngle / 360 * 255;
 int nSValue = S * 100;
 int nLValue = I * 100;
 h = nHValue;
 s = nSValue;
 i = nLValue;
}