标签:
在做图像处理时,我们一般采用的是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*Y
1/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)=t
1/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=039R+050G+011B转换为一个亮度信号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;
}
2.HSB(HSV) 通过色相/饱和度/亮度三要素来表达颜色.
H(Hue):表示颜色的类型(例如红色,绿色或者黄色).取值范围为0—360.其中每一个值代表一种颜色.
S(Saturation):颜色的饱和度.从0到1.有时候也称为纯度.(0表示灰度图,1表示纯的颜色)
B(Brightness or Value):颜色的明亮程度.从0到1.(0表示黑色,1表示特定饱和度的颜色)
后面地址是一个在线的观察RGB到HSB转换的工具:http://web.bentley.edu/empl/c/ncarter/MA307/color-converter.html
用RGB来表示颜色虽然方便,但是两个相近的颜色的RGB值却可能相差十万八千里。用HSV(Hue色相、Saturation饱和度、Value(Brightness)明度,也叫HSB)来表示颜色就比较符合人们的习惯。
RGB到HSV(HSB)的转换:
HSV(HSB)到RGB的转换:
根据以上说明,有以下转换公式(Java代码):
几种颜色模型的转换公式
XYZ —> RGB
var_X = X / 100 //X from 0 to 95.047
var_Y = Y / 100 //Y from 0 to 100.000
var_Z = Z / 100 //Z from 0 to 108.883
var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986
var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415
var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570
if ( var_R > 0.0031308 ) var_R = 1.055 * ( var_R ^ ( 1 / 2.4 ) ) - 0.055
else var_R = 12.92 * var_R
if ( var_G > 0.0031308 ) var_G = 1.055 * ( var_G ^ ( 1 / 2.4 ) ) - 0.055
else var_G = 12.92 * var_G
if ( var_B > 0.0031308 ) var_B = 1.055 * ( var_B ^ ( 1 / 2.4 ) ) - 0.055
else var_B = 12.92 * var_B
R = var_R * 255
G = var_G * 255
B = var_B * 255
RGB —> XYZ
var_R = ( R / 255 ) //R from 0 to 255
var_G = ( G / 255 ) //G from 0 to 255
var_B = ( B / 255 ) //B from 0 to 255
if ( var_R > 0.04045 ) var_R = ( ( var_R + 0.055 ) / 1.055 ) ^ 2.4
else var_R = var_R / 12.92
if ( var_G > 0.04045 ) var_G = ( ( var_G + 0.055 ) / 1.055 ) ^ 2.4
else var_G = var_G / 12.92
if ( var_B > 0.04045 ) var_B = ( ( var_B + 0.055 ) / 1.055 ) ^ 2.4
else var_B = var_B / 12.92
var_R = var_R * 100
var_G = var_G * 100
var_B = var_B * 100
X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805
Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505
XYZ —> Yxy
//X from 0 to 95.047
//Y from 0 to 100.000
//Z from 0 to 108.883
Y = Y
x = X / ( X + Y +Z )
y = Y / ( X + Y +Z )
Yxy —> XYZ
//Y from 0 to 100
//x from 0 to 1
//y from 0 to 1
X = x * ( Y / y )
Y = Y
Z = ( 1 - x - y ) * ( Y / y )
XYZ —> Hunter-Lab
(H)L = 10 * sqrt( Y )
(H)a = 17.5 * ( ( ( 1.02 * X ) - Y ) / sqrt(Y ) )
(H)b = 7 * ( ( Y - ( 0.847 * Z ) ) / sqrt(Y ) )
Hunter-Lab —> XYZ
var_Y = (H)L / 10
var_X = (H)a / 17.5 * (H)L / 10
var_Z = (H)b / 7 * (H)L / 10
Y = var_Y ^ 2
X = ( var_X + Y ) / 1.02
Z = -( var_Z - Y ) / 0.847
XYZ —> CIE-L*ab
var_X = X / ref_X //ref_X = 95.047
var_Y = Y / ref_Y //ref_Y = 100.000
var_Z = Z / ref_Z //ref_Z = 108.883
if ( var_X > 0.008856 ) var_X = var_X ^ ( 1/3 )
else var_X = ( 7.787 * var_X ) + ( 16 / 116 )
if ( var_Y > 0.008856 ) var_Y = var_Y ^ ( 1/3 )
else var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )
if ( var_Z > 0.008856 ) var_Z = var_Z ^ ( 1/3 )
else var_Z = ( 7.787 * var_Z ) + ( 16 / 116 )
CIE-L* = ( 116 * var_Y ) - 16
CIE-a* = 500 * ( var_X - var_Y )
CIE-b* = 200 * ( var_Y - var_Z )
CIE-L*ab —> XYZ
var_Y = ( CIE-L* + 16 ) / 116
var_X = CIE-a* / 500 + var_Y
var_Z = var_Y - CIE-b* / 200
if ( var_Y^3 > 0.008856 ) var_Y = var_Y^3
else var_Y = ( var_Y - 16 / 116 ) / 7.787
if ( var_X^3 > 0.008856 ) var_X = var_X^3
else var_X = ( var_X - 16 / 116 ) / 7.787
if ( var_Z^3 > 0.008856 ) var_Z = var_Z^3
else var_Z = ( var_Z - 16 / 116 ) / 7.787
X = ref_X * var_X //ref_X = 95.047
Y = ref_Y * var_Y //ref_Y = 100.000
Z = ref_Z * var_Z //ref_Z = 108.883
CIE-L*ab —> CIE-L*CH°
var_H = arc_tangent( CIE-b*, CIE-a* ) //Quadrant by signs
if ( var_H > 0 ) var_H = ( var_H / PI ) * 180
else var_H = 360 - ( abs( var_H ) / PI ) * 180
CIE-L* = CIE-L*
CIE-C* = sqrt( CIE-a* ^ 2 + CIE-b* ^ 2 )
CIE-H° = var_H
CIE-L*CH° —>CIE-L*ab
//CIE-H° from 0 to 360°
CIE-L* = CIE-L*
CIE-a* = cos( degree_2_radian( CIE-H° ) ) *CIE-C*
CIE-b* = sin( degree_2_radian( CIE-H° ) ) *CIE-C*
XYZ —> CIE-L*uv
var_U = ( 4 * X ) / ( X + ( 15 * Y ) + ( 3 * Z ) )
var_V = ( 9 * Y ) / ( X + ( 15 * Y ) + ( 3 *Z ) )
var_Y = Y / 100
if ( var_Y > 0.008856 ) var_Y = var_Y ^ ( 1/3 )
else var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )
ref_X = 95.047
ref_Y = 100.000
ref_Z = 108.883
ref_U = ( 4 * ref_X ) / ( ref_X + ( 15 * ref_Y ) + ( 3 * ref_Z ) )
ref_V = ( 9 * ref_Y ) / ( ref_X + ( 15 * ref_Y ) + ( 3 * ref_Z ) )
CIE-L* = ( 116 * var_Y ) - 16
CIE-u* = 13 * CIE-L* * ( var_U - ref_U )
CIE-v* = 13 * CIE-L* * ( var_V - ref_V )
CIE-L*uv —> XYZ
var_Y = ( CIE-L* + 16 ) / 116
if ( var_Y^3 > 0.008856 ) var_Y = var_Y^3
else var_Y = ( var_Y - 16 / 116 ) / 7.787
ref_X = 95.047
ref_Y = 100.000
ref_Z = 108.883
ref_U = ( 4 * ref_X ) / ( ref_X + ( 15 * ref_Y ) + ( 3 * ref_Z ) )
ref_V = ( 9 * ref_Y ) / ( ref_X + ( 15 * ref_Y ) + ( 3 * ref_Z ) )
var_U = CIE-u* / ( 13 * CIE-L* ) + ref_U
var_V = CIE-v* / ( 13 * CIE-L* ) + ref_V
Y = var_Y * 100
X = - ( 9 * Y * var_U ) / ( ( var_U - 4 ) * var_V - var_U * var_V )
Z = ( 9 * Y - ( 15 * var_V * Y ) - ( var_V * X ) ) / ( 3 * var_V )
RGB —> HSL
var_R = ( R / 255 ) //RGB from 0 to 255
var_G = ( G / 255 )
var_B = ( B / 255 )
var_Min = min( var_R, var_G, var_B ) //Min. value of RGB
var_Max = max( var_R, var_G, var_B ) //Max. value of RGB
del_Max = var_Max - var_Min //Delta RGB value
L = ( var_Max + var_Min ) / 2
if ( del_Max == 0 ) //This is a gray, no chroma...
{
H = 0 //HSL results from 0 to 1
S = 0
}
else //Chromatic data...
{
if ( L < 0.5 ) S = del_Max / ( var_Max + var_Min )
else S = del_Max / ( 2 - var_Max - var_Min )
del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max
del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max
del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max
if ( var_R == var_Max ) H = del_B - del_G
else if ( var_G == var_Max ) H = ( 1 / 3 ) + del_R - del_B
else if ( var_B == var_Max ) H = ( 2 / 3 ) + del_G - del_R
if ( H < 0 ) ; H += 1
if ( H > 1 ) ; H -= 1
}
HSL —> RGB
if ( S == 0 ) //HSL from 0 to 1
{
R = L * 255 //RGB results from 0 to 255
G = L * 255
B = L * 255
}
else
{
if ( L < 0.5 ) var_2 = L * ( 1 + S )
else var_2 = ( L + S ) - ( S * L )
var_1 = 2 * L - var_2
R = 255 * Hue_2_RGB( var_1, var_2, H + ( 1 / 3 ) )
G = 255 * Hue_2_RGB( var_1, var_2, H )
B = 255 * Hue_2_RGB( var_1, var_2, H - ( 1 / 3 ) )
}
Hue_2_RGB( v1, v2, vH ) //Function Hue_2_RGB
{
if ( vH < 0 ) vH += 1
if ( vH > 1 ) vH -= 1
if ( ( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH )
if ( ( 2 * vH ) < 1 ) return ( v2 )
if ( ( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 )
return ( v1 )
}
RGB —> HSV
var_R = ( R / 255 ) //RGB from 0 to 255
var_G = ( G / 255 )
var_B = ( B / 255 )
var_Min = min( var_R, var_G, var_B ) //Min. value of RGB
var_Max = max( var_R, var_G, var_B ) //Max. value of RGB
del_Max = var_Max - var_Min //Delta RGB value
V = var_Max
if ( del_Max == 0 ) //This is a gray, no chroma...
{
H = 0 //HSV results from 0 to 1
S = 0
}
else //Chromatic data...
{
S = del_Max / var_Max
del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max
del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max
del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max
if ( var_R == var_Max ) H = del_B - del_G
else if ( var_G == var_Max ) H = ( 1 / 3 ) + del_R - del_B
else if ( var_B == var_Max ) H = ( 2 / 3 ) + del_G - del_R
if ( H < 0 ) ; H += 1
if ( H > 1 ) ; H -= 1
}
HSV —> RGB
if ( S == 0 ) //HSV from 0 to 1
{
R = V * 255
G = V * 255
B = V * 255
}
else
{
var_h = H * 6
if ( var_h == 6 ) var_h = 0 //H must be < 1
var_i = int( var_h ) //Or ... var_i = floor( var_h )
var_1 = V * ( 1 - S )
var_2 = V * ( 1 - S * ( var_h - var_i ) )
var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) )
if ( var_i == 0 ) { var_r = V ; var_g = var_3 ; var_b = var_1 }
else if ( var_i == 1 ) { var_r = var_2 ; var_g = V ; var_b = var_1 }
else if ( var_i == 2 ) { var_r = var_1 ; var_g = V ; var_b = var_3 }
else if ( var_i == 3 ) { var_r = var_1 ; var_g = var_2 ; var_b = V }
else if ( var_i == 4 ) { var_r = var_3 ; var_g = var_1 ; var_b = V }
else { var_r = V ; var_g = var_1 ; var_b = var_2 }
R = var_r * 255 //RGB results from 0 to 255
G = var_g * 255
B = var_b * 255
}
RGB —> CMY
//RGB values from 0 to 255
//CMY results from 0 to 1
C = 1 - ( R / 255 )
M = 1 - ( G / 255 )
Y = 1 - ( B / 255 )
CMY —> RGB
//CMY values from 0 to 1
//RGB results from 0 to 255
R = ( 1 - C ) * 255
G = ( 1 - M ) * 255
B = ( 1 - Y ) * 255
CMY —> CMYK
//CMYK and CMY values from 0 to 1
var_K = 1
if ( C < var_K ) var_K = C
if ( M < var_K ) var_K = M
if ( Y < var_K ) var_K = Y
if ( var_K == 1 ) { //Black
C = 0
M = 0
Y = 0
}
else {
C = ( C - var_K ) / ( 1 - var_K )
M = ( M - var_K ) / ( 1 - var_K )
Y = ( Y - var_K ) / ( 1 - var_K )
}
K = var_K
CMYK —> CMY
//CMYK and CMY values from 0 to 1
C = ( C * ( 1 - K ) +K )
M = ( M * ( 1 - K ) + K )
Y = ( Y * ( 1 - K ) + K )
标签:
原文地址:http://www.cnblogs.com/Free-Thinker/p/4831903.html