[转]数字图像处理 颜色空间RGB、HSI、CMYK、YUV的相互转换

原理介绍:

 

颜色空间也称彩色模型(又称彩色空间或彩色系统)它的用途是在某些标准下用通常可接受的方式对彩色加以说明。 本质上,彩色模型是坐标系统和子空间的阐述。位于系统的每种颜色都有单个点表示。现在使用的彩色模型很多,主要是由于彩色科学是一个包括很多应用的很宽的领域。 在彩色图像处理中,选择合适的彩色模型是很重要的。从应用的角度来看,人们提出的众多彩色模型可以分为两类。一类面向诸如彩色显示器或彩色打印机之类输出显示场合使用的硬设备。另一类面向视觉感知或者说以彩色处理分析为目的的应用,如动画中的彩色图形,各种图像处理的算法等。 

 

RGB(红绿蓝)

 
RGB是依据人眼识别的颜色定义出的空间,可表示大部分颜色。是图像处理中最基本、最常用、面向硬件的颜色空间,是一种光混合的体系。
 
RGB颜色空间最常用的用途就是显示器系统,彩色阴极射线管,彩色光栅图形的显示器都使用R、G、B数值来驱动R、G、B 电子枪发射电子,并分别激发荧光屏上的R、G、B三种颜色的荧光粉发出不同亮度的光线,并通过相加混合产生各种颜色。扫描仪也是通过吸收原稿经反射或透射而发送来的光线中的R、G、B成分,并用它来表示原稿的颜色。
 
模型:
 
 
可以看到RGB颜色模式用三维空间中的一个点表示一种颜色,每个点有三个分量,分别表示红、绿、蓝的亮度值,亮度值限定为【0,1】。在RGB模型的立方体中,原点对应的颜色为黑色,它的三个分量值都为0;距离原点最远的顶点对应的颜色为白色,它的三个分量值都为1。从黑色到白色的灰度值分布在这两个点的连线上,该虚线称为灰度线;立方体的其余各点对应不同的颜色,即三原色红、绿、蓝及其混合色黄、品红、青色。
 

HSI

 
HSI色彩空间是从人的视觉系统出发,用色调(Hue)、饱和度(Saturation或Chroma)和亮度 (Intensity或Brightness)来描述色彩。
 
H——表示颜色的相位角。红、绿、蓝分别相隔120度;互补色分别相差180度,即颜色的类别。
S——表示成所选颜色的纯度和该颜色最大的纯度之间的比率,范围:[0,  1],即颜色的深浅程度。
I——表示色彩的明亮程度,围:[0, 1],人眼对亮度很敏感!
 
模型:
 

 
可以看到HSI色彩空间和RGB色彩空间只是同一物理量的不同表示法,因而它们之间存在着转换关系:HSI颜色模式中的色调使用颜色类别表示,饱和度与颜色的白光光亮亮度刚好成反比,代表灰色与色调的比例,亮度是颜色的相对明暗程度。
 

CMYK

 
CMYK是一种依靠反光的色彩模式,我们是怎样阅读报纸的内容呢?是由阳光或灯光照射到报纸上,再反射到我们的眼中,才看到内容。它需要有外界光源,如果你在黑暗房间内是无法阅读报纸的。只要在屏幕上显示的图像,就是RGB模式表现的。只要是在印刷品上看到的图像,就是CMYK模式表现的。大多数在纸上沉积彩色颜料的设备,如彩色打印机和复印机,要求输入CMY数据,在内部进行RGB到CMY的转换。
 
模型:
 

 
青色Cyan、品红色Magenta、黄色Yellow是光的二次色,是颜料的颜色。而K取的是black最后一个字母,之所以不取首字母,是为了避免与蓝色(Blue)混淆。当红绿蓝三原色被混合时,会产生白色,当混合青色、品红色、黄色三原色时会产生黑色。从理论上来说,只需要CMY三种油墨就足够了,但是由于目前制造工艺还不能造出高纯度的油墨,CMY相加的结果实际是一种暗红色。
 

YUV

 
YUV 颜色空间在 PAL,NTSC和 SECAM复合颜色视频标准中使用。采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。黑白电视系统只使用亮度信号(Y);彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,色度信号(U,V)以一种特殊的方式加入亮度信号,这样,黑白电视接收机能够显示正常的黑白图像,而彩色电视接收机能够对对附加的色度信号进行解码从而显示彩色图像。
 
人眼对色度的敏感程度要低于对亮度的敏感程度。人类视网膜上的视网膜杆细胞要多于视网膜锥细胞,说得通俗一些,视网膜杆细胞的作用就是识别亮度,而视网膜锥细胞的作用就是识别色度。所以,你的眼睛对于亮和暗的分辨要比对颜色的分辨精细一些。正是因为这个,在我们的视频存储中,没有必要存储全部颜色信号。所以把YUV分开存储,Y信号是黑白信号,是以全分辨率存储的,而色度信号并不是用全分辨率存储的。
 
模式:
 



颜色空间是一系列颜色的数学表现形式。三种最流行的颜色模型是RGB(用于计算机图形);YIQ,YUV或YCbCr(用于视频系统)和CMYK(用于彩色打印)。但是,这三种颜色没有一种和我们直觉概念上的色调,饱和度,亮度有直接的联系。这就使我们暂时去追寻其它的模型,如HIS和HSV,它们能简化编程,处理和终端用户操作。

RGB与HSI转换

 

RGB转HSI

 
 

HSI转RGB

 
给定 HSI空间中的 (h, s, l) 值定义的一个颜色,带有 h 在指示色相角度的值域 [0, 360)中,分别表示饱和度和亮度的s 和 l 在值域 [0, 1] 中,相应在 RGB 空间中的 (r, g, b) 三原色,带有分别对应于红色、绿色和蓝色的 r, g 和 b 也在值域 [0, 1] 中,它们可计算为:

首先,如果 s = 0,则结果的颜色是非彩色的、或灰色的。在这个特殊情况,r, g 和 b 都等于 l。注意 h 的值在这种情况下是未定义的。当 s ≠ 0 的时候,可以使用下列过程:
 
 

RGB转CMYK

 
 

RGB与YUV 转换

 
伽马校正后的转换
 
 
 

源码

 
考虑到RGB与CMYK、YUV转换很简单,所以这里展示RGB与HSI颜色互转的C++代码
//================================================================================  
/// @brief HLS <====> RGB  
///  
/// [1]H是色相,代表了6种颜色,分成0~6区域,用一个模型来表述就是一个双(六)棱椎,其中的L是HSL立方体的主对角线。  
//     RGB立方体的顶点:红、黄、绿、青、蓝和品红就成为HSL六角形的顶点,0-360度的范围内有6种颜色,但是它不是平均分布的,如绿色最多.  
///    H是0-360,L和S是0.00%-100.00%    
//================================================================================  
//HLS ---> RGB  
void RGBtoHLS (int rgb, double& H, double& L, double& S)  
{  
    Color color(rgb);  
    RGBtoHLS(color.R, color.G, color.B, H, L, S);  
}  
  
//HLS ---> RGB  
void RGBtoHLS (int r, int g, int b, double& H, double& L, double& S)  
{  
    int   n_cmax = max(r, max(g, b));  
    int   n_cmin = min(r, min(g, b));  
  
    double Delta = 0;  
    double Max = 0, Min = 0;  
    double Redf = 0, Greenf = 0, Bluef = 0;  
  
    Redf    = (r / 255.0f);  
    Greenf  = (g / 255.0f);  
    Bluef   = (b / 255.0f);   
  
    Max     = max(max(Redf, Greenf), Bluef);  
    Min     = min(min(Redf, Greenf), Bluef);  
  
    H = 0;  
    L = (Max + Min) / 2.0f;  
    S = 0;  
  
    if (Max == Min)  
    {  
        return;  
    }  
  
    Delta = (Max - Min);  
    if (L < 0.5)  
        S = Delta / (Max + Min);  
    else  
        S = Delta / (2.0 - Max - Min);  
  
    if (Redf == Max)  
    {  
        if (Greenf >= Bluef)  
        {  
            H = (Greenf - Bluef) / Delta;  
        }  
        else  
        {  
            H = 6.0 + (Greenf - Bluef) / Delta;  
        }  
    }         
    else if (Greenf == Max)  
        H = 2.0 + (Bluef - Redf) / Delta;  
    else  
        H = 4.0 + (Redf - Greenf) / Delta;  
  
    H /= 6.0; //除以6,表示在那个部分。  
  
    if (H < 0.0)  
        H += 1.0;     
    if (H > 1)  
        H -= 1;  
  
    H = (int)(H * 360); //转成[0, 360]  
}  
  
void Color_HueToRgb(double p, double q, double Ht, double *Channel)  
{  
    if (Ht < 0.0)  
        Ht += 1.0;  
    else if (Ht > 1.0)  
        Ht -= 1.0;  
  
    if ((6.0 * Ht) < 1.0)  
        *Channel = (p + (q - p) * Ht * 6.0);  
    else if ((2.0 * Ht) < 1.0)  
        *Channel = (q);  
    else if ((3.0 * Ht) < 2.0)  
        *Channel = (p + (q - p) * ((2.0F / 3.0F) - Ht) * 6.0);  
    else  
        *Channel = (p);  
}  
  
//RGB ---> HLS  
void HLStoRGB (double H, double L, double S, BYTE &r, BYTE &g, BYTE &b)  
{  
    double M1 = 0, M2 = 0;  
    double Redf = 0, Greenf = 0, Bluef = 0;  
  
    double hue = H / 360;  
  
    if (S == 0)//灰色  
    {  
        Redf    = L;  
        Greenf  = L;  
        Bluef   = L;  
    }  
    else  
    {  
        if (L <= 0.5)  
            M2 = L * (1.0 + S);  
        else  
            M2 = L + S - L * S;  
  
        M1 = (2.0 * L - M2);  
  
        Color_HueToRgb(M1, M2, hue + (1.0F / 3.0F), &Redf);  
        Color_HueToRgb(M1, M2, hue, &Greenf);  
        Color_HueToRgb(M1, M2, hue - (1.0F / 3.0F), &Bluef);  
    }  
  
    r = (BYTE)(Redf * 255);  
    g = (BYTE)(Bluef * 255);  
    b = (BYTE)(Greenf * 255);  
}  

  

posted @ 2017-08-08 10:49  ZYVV  阅读(1865)  评论(0)    收藏  举报