zoukankan      html  css  js  c++  java
  • 图像的颜色空间


    色彩的三要素 —— 色相、明度、纯度

    • H色相(表,表现):即色彩的相貌和特征。自然界中色彩的种类很多,色相指色彩的种类和名称。如;红、橙、黄、绿、青、蓝、紫等等颜色的种类变化就叫色相。

    • B明度(表,面子):指色彩的亮度或明度,也叫明亮度。颜色有深浅、明暗的变化。比如,深黄、中黄、淡黄、柠檬黄等黄颜色在明度上就不一样,紫红、深红、玫瑰红、大红、朱红、桔红等红颜色在亮度上也不尽相同。这些颜色在明暗、深浅上的不同变化,也就是色彩的又一重要特征一一明度变化。
      色彩的明度变化有许多种情况,一是不同色相之间的明度变化。如:白比黄亮、黄比橙亮、橙比红亮、红比紫亮、紫比黑亮;二是在某种颜色中加白色,亮度就会逐渐提高,加黑色亮度就会变暗,但同时它们的纯度(颜色的饱和度)就会降低,三是相同的颜色,因光线照射的强弱不同也会产生不同的明暗变化。。

    • S纯度(里,里子):指色彩的鲜艳程度,也叫饱和度。原色是纯度最高的色彩。颜色混合的次数越多,纯度越低,反之,纯度则高。原色中混入补色,纯度会立即降低、变灰。物体本身的色彩,也有纯度高低之分,西红柿与苹果相比,西红柿的纯度高些,苹果的纯度低些。

    关于水的色彩观念 —— 水,首先是无色的;其次是白色的(可以降低纯度,提高明度;最后是任意色的(经光照反色多彩或折射七彩)。

    HSB,S=纯色/白色,B就看作一盏灯(通过“0%黑色”到“100%黑色”来模拟这盏灯的亮度值)

    B灯你也可以看作黑暗程度,其值为0的时候,就当B属性不存在,只显示“颜色另两个属性”。其值>0%时表示B灯启动,对“颜色另两个属性”开始发生作用。

    HSL,S=纯色/50%灰色,L也看作一盏灯(但它模拟的方式和HSB中的B不同,“<50%”代表黑色的量,50%代表白色和黑色的量都为0,“>50%~100%”代表白色的量)

    L灯可以看作一盏“两极灯”,它有黑暗和光明两个端点,维持在当中的50%时表示L属性不存在,只显示“颜色另两个属性”。其值向两级移动时表示L灯启动,对“颜色另两个属性”开始发生作用。


    HSL色彩模型又是什么?
    HSL同样使用了3个分量来描述色彩,与RGB使用的三色光不同,HSL色彩的表述方式是:H(hue)色相,S(saturation)饱和度,以及L(lightness)亮度。
    听起来一样复杂?稍后你就会发现,与“反人类”的RGB模型相比,HSL是多么的友好。

    • HSL的H(hue)分量,代表的是人眼所能感知的颜色范围,这些颜色分布在一个平面的色相环上,取值范围是0°到360°的圆心角,每个角度可以代表一种颜色。色相值的意义在于,我们可以在不改变光感的情况下,通过旋转色相环来改变颜色。在实际应用中,我们需要记住色相环上的六大主色,用作基本参照:360°/0°红、60°黄、120°绿、180°青、240°蓝、300°洋红,它们在色相环上按照60°圆心角的间隔排列。

    ![HSL之色相]
    • HSL的S(saturation)分量,指的是色彩的饱和度,它用0%至100%的值描述了相同色相、明度下色彩纯度的变化。数值越大,颜色中的灰色越少,颜色越鲜艳,呈现一种从理性(灰度)到感性(纯色)的变化。

    ![HSL之饱和度]
    • HSL的L(lightness)分量,指的是色彩的明度,作用是控制色彩的明暗变化。它同样使用了0%至100%的取值范围。数值越小,色彩越暗,越接近于黑色;数值越大,色彩越亮,越接近于白色。


    ![HSL之明度]


    采用HSL颜色体系后, 更能便捷地选取自己偏好或当前合适的颜色.

    特别对于随机色的表示, 采用RGB可能不太友好(有时偏暗, 外观不佳), 可试试HSL. 如下所示(仅示范, 细心调试后更佳):
    CGFloat hue = ( arc4random() % 256 / 256.0 ); // 0.0 to 1.0
    CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from white
    CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from black
    UIColor *color = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1.0];

    形式定义

    HSL 和 HSV 在数学上定义为在 RGB 空间中的颜色的 RG 和 B 的坐标的变换。

    [编辑]从 RGB 到 HSL 或 HSV 的转换

    设 (rgb) 分别是一个颜色的红、绿和蓝坐标,它们的值是在 0 到 1 之间的实数。设 max 等价于 rg 和 b 中的最大者。设 min 等于这些值中的最小者。要找到在 HSL 空间中的 (hsl) 值,这里的 h ∈ [0, 360)是角度的色相角,而 sl ∈ [0,1] 是饱和度和亮度,计算为:

    h =egin{cases}0^circ & mbox{if } max = min \60^circ 	imes frac{g - b}{max - min} + 0^circ,   & mbox{if } max = r mbox{ and } g ge b \60^circ 	imes frac{g - b}{max - min} + 360^circ,   & mbox{if } max = r mbox{ and } g < b \60^circ 	imes frac{b - r}{max - min} + 120^circ, & mbox{if } max = g \60^circ 	imes frac{r - g}{max - min} + 240^circ, & mbox{if } max = bend{cases}
    l = egin{matrix} frac{1}{2} end{matrix} (max + min)
    s = egin{cases}0 & mbox{if } l = 0 mbox{ or } max = min \frac{max-min}{max+min} = frac{max-min}{2l}, & mbox{if } 0  frac{1}{2}end{cases}


    h 的值通常规范化到位于 0 到 360°之间。而 h = 0 用于 max = min 的(就是灰色)时候而不是留下 h 未定义。

    HSL 和 HSV 有同样的色相定义,但是其他分量不同。HSV 颜色的 s 和 v 的值定义如下:

    s = egin{cases}0, & mbox{if } max = 0 \frac{max - min}{max} = 1 - frac{min}{max}, & mbox{otherwise}end{cases}
    v = max \,

    [编辑]从 HSL 到 RGB 的转换

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

    首先,如果 s = 0,则结果的颜色是非彩色的、或灰色的。在这个特殊情况,rg 和 b 都等于 l。注意 h 的值在这种情况下是未定义的。

    当 s ≠ 0 的时候,可以使用下列过程:[1]

    q=egin{cases}l 	imes (1+s), & mbox{if } l < frac{1}{2} \l+s-(l 	imes s), & mbox{if } l ge frac{1}{2}end{cases}
    p = 2 	imes l - q \,
    h_k = {h over 360} \, h 规范化到值域 [0,1)内)
    t_R = h_k+frac{1}{3} \,
    t_G = h_k \,
    t_B = h_k-frac{1}{3} \,
    mbox{if } t_C < 0 
ightarrow t_C = t_C + 1.0 quad mbox{for each}\,C in {R,G,B}
    mbox{if } t_C > 1 
ightarrow t_C = t_C - 1.0 quad mbox{for each}\,C in {R,G,B}


    对于每个颜色向量 Color = (ColorRColorGColorB) = (rgb),

    {Color}_C =egin{cases}p+ left((q-p) 	imes 6 	imes t_C
ight), & mbox{if } t_C < frac{1}{6}  \q, & mbox{if } frac{1}{6} le t_C < frac{1}{2}  \p+left((q-p) 	imes 6 	imes (frac{2}{3} - t_C) 
ight), & mbox{if } frac{1}{2} le t_C < frac{2}{3} \p, & mbox{otherwise }end{cases}
    mbox{for each}\,C in {R,G,B}

    [编辑]从 HSV 到 RGB 的转换

    类似的,给定在 HSV 中 (hsv) 值定义的一个颜色,带有如上的 h,和分别表示饱和度和明度的 s 和 v 变化于 0 到 1 之间,在 RGB 空间中对应的 (rgb) 三原色可以计算为:

    h_i equiv leftlfloor frac{h}{60} 
ight
floor pmod{6}
    f = frac{h}{60} - h_i
    p = v 	imes (1 - s) \,
    q = v 	imes (1 - f 	imes s) \,
    t = v 	imes (1 - (1 - f) 	imes s) \,


    对于每个颜色向量 (rgb),

    (r, g, b) = egin{cases}(v, t, p), & mbox{if } h_i = 0  \(q, v, p), & mbox{if } h_i = 1  \(p, v, t), & mbox{if } h_i = 2  \(p, q, v), & mbox{if } h_i = 3  \(t, p, v), & mbox{if } h_i = 4  \(v, p, q), & mbox{if } h_i = 5  \end{cases}


    展示的 RGB 值的范围是 0.0 到 1.0。

    RGBHSLHSV结果
    (1, 0, 0) (0°, 1, 0.5) (0°, 1, 1)  
    (0.5, 1, 0.5) (120°, 1, 0.75) (120°, 0.5, 1)  
    (0, 0, 0.5) (240°, 1, 0.25) (240°, 1, 0.5)  
     
    //(1)Matlab RGB转换为HSV
    
    I = imread('Lena.jpg');
    HSV = rgb2hsv(I);
    H = HSV(:, :, 1);
    S = HSV(:, :, 2);
    V = HSV(:, :, 3);
    figure;
    subplot(2, 3, 1); imshow(I);
    //subplot(2, 3, 2); imshow(HSV);
    subplot(2, 3, 4); imshow(H);
    subplot(2, 3, 5); imshow(S);
    subplot(2, 3, 6); imshow(V);
    //(2)Opencv中RGB转换为HSV
    
    // BRGtoHSVShow.cpp : 定义控制台应用程序的入口点。
    //
    
    //#include "stdafx.h"
    #include "cv.h"
    #include "cxcore.h"
    #include "highgui.h"
    #include "cvaux.h"
    
    int main( )
    {
     IplImage* src = NULL;
     IplImage* floatsrc = NULL;
     IplImage* floathsv = NULL;
     IplImage* floatimgH = NULL;
     IplImage* floatimgS = NULL;
     IplImage* floatimgV = NULL;
    
     cvNamedWindow( "src", 1 );
     cvNamedWindow( "H通道", 1 );
     cvNamedWindow( "S通道", 1 );
     cvNamedWindow( "V通道", 1 );
    
     src = cvLoadImage( "lena.jpg", -1);
    cvShowImage( "src", src );
     CvSize size = cvGetSize( src );
    
     //先将图像转换成float型的
     floatsrc = cvCreateImage( size, IPL_DEPTH_32F, 3 );
     floathsv = cvCreateImage( size, IPL_DEPTH_32F, 3 );
     floatimgH = cvCreateImage( size, IPL_DEPTH_32F, 1 );
     floatimgS = cvCreateImage( size, IPL_DEPTH_32F, 1 );
     floatimgV = cvCreateImage( size, IPL_DEPTH_32F, 1 );
    
     //将src从8位转换到32位的float型
     cvConvertScale( src, floatsrc, 1.0/255.0, 0 );//归一化之后方能够显示
     //cvConvertScale( src, floatsrc, 1, 0 );
     //cvShowImage("floatsrc",floatsrc);
     //cvWaitKey(-1);
    
     //将float型图像 从BGR转换到HSV  如果需要转换到其他的颜色空间 那么改变CV_BGR2HSV即可
     //cvCvtColor要求两个参数的类型必须完全相同,所以要转为float型
     cvCvtColor( floatsrc, floathsv, CV_BGR2HSV );
    
     //将三通道图像 分解成3个单通道图像,H对应的通道时0,S、V对应的通道时1和2
     //cvCvtPixToPlane(picHSV, h_plane, s_plane, v_plane, 0);
     cvSplit( floathsv, floatimgH, floatimgS, floatimgV, NULL);
    
     cvShowImage( "src", src );
     cvShowImage( "H通道", floatimgH );
     cvShowImage( "S通道", floatimgS );
     cvShowImage( "V通道", floatimgV );
    //CV_BGR2HSV
    
     cvWaitKey( 0 );
    
     cvReleaseImage( &src );
     cvReleaseImage( &floathsv );
     cvReleaseImage( &floatimgH );
     cvReleaseImage( &floatimgS );
     cvReleaseImage( &floatimgV );
    
     return 0;
    }
    
     

    HIS模型反应了人的视觉系统观察彩色的方式,使用非常接近于人对彩色感知的方式来定义彩色。对于图像处理来说,这种模型的优

    势在于将颜色信息和灰度信息分开了。色调(Hue)分量是描述一种纯色的颜色属性(如红色,绿色,黄色),饱和度(Saturation)分量是一

    种纯色被白光稀释的程度的度量,也可以理解为颜色的浓淡程度(如深红色,淡绿色),亮度(Instensity)分量描述颜色的亮暗程度。这个

    模型的建立基于以下两个重要事实:

           I分量与图像的色彩信息无关; 

             H和S分量与人感受颜色的方式紧密相连。

    HIS颜色空间,如下图所示:

    正因为在HIS彩色空间中亮度和色度是互相分离的,所以在彩色图像分割应用中具有较大优势。但是目前很少有硬件设备支持这种彩

    色模型,因此需要从其他颜色空间进行转换。

     

    以下是几种常用的RGB-HSI转换公式:

     

    以下是对这几种转换方式的对比

     一个例子:

    核心的转换公式:

    RGB-->HSI

    截图来自中科院刘定生老师的《数字图像处理与分析》课件。

    HSI-->RGB

    具体的数学公式参照冈萨雷斯版《数字图像处理(第三版)》432-434页,中译版的260-261页。

    下面贴代码:

    #include "opencv_libs.h"
    #include <highgui.h>
    #include <cv.h>
    #include <math.h>
    
    /*
     * 描述:实现RGB颜色模型到HSI颜色模型之间的相互转换
     * 作者:qdsclove(qdsclove@gmail.com)
     * 时间:16:01 4/17 星期三 2013
     */
    
    // 将HSI颜色空间的三个分量组合起来,便于显示
    IplImage* catHSImage(CvMat* HSI_H, CvMat* HSI_S, CvMat* HSI_I)
    {
        IplImage* HSI_Image = cvCreateImage( cvGetSize( HSI_H ), IPL_DEPTH_8U, 3 );
    
        for(int i = 0; i < HSI_Image->height; i++)
        {
            for(int j = 0; j < HSI_Image->width; j++)
            {
                double d = cvmGet( HSI_H, i, j );
                int b = (int)(d * 255/360);
                d = cvmGet( HSI_S, i, j );
                int g = (int)( d * 255 );
                d = cvmGet( HSI_I, i, j );
                int r = (int)( d * 255 );
    
                cvSet2D( HSI_Image, i, j, cvScalar( b, g, r ) );
            }
        }
    
        return HSI_Image;
    }
    
    // 将HSI颜色模型的数据转换为RGB颜色模型的图像
    IplImage* HSI2RGBImage(CvMat* HSI_H, CvMat* HSI_S, CvMat* HSI_I)
    {
        IplImage * RGB_Image = cvCreateImage(cvGetSize(HSI_H), IPL_DEPTH_8U, 3 );
    
        int iB, iG, iR;
        for(int i = 0; i < RGB_Image->height; i++)
        {
            for(int j = 0; j < RGB_Image->width; j++)
            {
                // 该点的色度H
                double dH = cvmGet( HSI_H, i, j );
                // 该点的色饱和度S
                double dS = cvmGet( HSI_S, i, j );
                // 该点的亮度
                double dI = cvmGet( HSI_I, i, j );
    
                double dTempB, dTempG, dTempR;
                // RG扇区
                if(dH < 120 && dH >= 0)
                {
                    // 将H转为弧度表示
                    dH = dH * 3.1415926 / 180;
                    dTempB = dI * (1 - dS);
                    dTempR = dI * ( 1 + (dS * cos(dH))/cos(3.1415926/3 - dH) );
                    dTempG = (3 * dI - (dTempR + dTempB)); 
                }
                // GB扇区
                else if(dH < 240 && dH >= 120)
                {
                    dH -= 120;
                                    
                    // 将H转为弧度表示
                    dH = dH * 3.1415926 / 180;
    
                    dTempR = dI * (1 - dS);
                    dTempG = dI * (1 + dS * cos(dH)/cos(3.1415926/3 - dH));
                    dTempB = (3 * dI - (dTempR + dTempG));
                }
                // BR扇区
                else 
                {
                    dH -= 240;
    
                    // 将H转为弧度表示
                    dH = dH * 3.1415926 / 180;
    
                    dTempG = dI * (1 - dS);
                    dTempB = dI * (1 + (dS * cos(dH))/cos(3.1415926/3 - dH));
                    dTempR = (3* dI - (dTempG + dTempB));
                }
    
                iB = dTempB * 255;
                iG = dTempG * 255;
                iR = dTempR * 255;
    
                cvSet2D( RGB_Image, i, j, cvScalar( iB, iG, iR ) );
            }
        }
    
        return RGB_Image;
    }
    
    
    int main()
    {
        IplImage* img = cvLoadImage("lena.bmp");
    
        // 三个HSI空间数据矩阵
        CvMat* HSI_H = cvCreateMat( img->height, img->width, CV_32FC1 );
        CvMat* HSI_S = cvCreateMat( img->height, img->width, CV_32FC1 );
        CvMat* HSI_I = cvCreateMat( img->height, img->width, CV_32FC1 );
    
        // 原始图像数据指针, HSI矩阵数据指针
        uchar* data;
    
        // rgb分量
        byte img_r, img_g, img_b;
        byte min_rgb;  // rgb分量中的最小值
        // HSI分量
        float fHue, fSaturation, fIntensity; 
    
        for(int i = 0; i < img->height; i++)
        {
            for(int j = 0; j < img->width; j++)
            {
                 data = cvPtr2D(img, i, j, 0);  
                 img_b = *data;
                 data++;
                 img_g = *data;
                 data++;
                 img_r = *data;
    
                 // Intensity分量[0, 1]
                 fIntensity = (float)((img_b + img_g + img_r)/3)/255;
    
                 // 得到RGB分量中的最小值
                 float fTemp = img_r < img_g ? img_r : img_g;
                 min_rgb = fTemp < img_b ? fTemp : img_b;
                 // Saturation分量[0, 1]
                 fSaturation = 1 - (float)(3 * min_rgb)/(img_r + img_g + img_b);
    
                 // 计算theta角
                 float numerator = (img_r - img_g + img_r - img_b ) / 2;
                 float denominator = sqrt( 
                     pow( (img_r - img_g), 2 ) + (img_r - img_b)*(img_g - img_b) );
    
                 // 计算Hue分量
                 if(denominator != 0)
                 {
                     float theta = acos( numerator/denominator) * 180/3.14;
                     
                     if(img_b <= img_g)
                     {
                         fHue = theta ;
                     }
                     else
                     {
                         fHue = 360 - theta;
                     }
                 }
                 else
                 {
                     fHue = 0;
                 }
    
                 // 赋值
                 cvmSet( HSI_H, i, j, fHue );
                 cvmSet( HSI_S, i, j, fSaturation);
                 cvmSet( HSI_I, i, j, fIntensity );
            }
        }
    
        IplImage* HSI_Image = catHSImage( HSI_H, HSI_S, HSI_I );
        IplImage* RGB_Image = HSI2RGBImage( HSI_H, HSI_S, HSI_I );
    
        cvShowImage("img", img);
        cvShowImage("HSI Color Model", HSI_Image);
        cvShowImage("RGB Color Model", RGB_Image);
    
        cvWaitKey(0);
    
        cvReleaseImage( &img );
        cvReleaseImage( &HSI_Image );
        cvReleaseImage( &RGB_Image );
        cvReleaseMat( &HSI_H);
        cvReleaseMat( &HSI_S);
        cvReleaseMat( &HSI_I);
    
        cvDestroyAllWindows();
    
        return 0;
    }
  • 相关阅读:
    并发和并行的区别
    fiddler-打断点(bpu)
    fiddler操作
    fiddler手机抓包
    面试题1
    Linux查看日志常用命令
    HTMLTestRunner
    mysql数据库无法插入特殊字符报错
    mybatis解决属性名和数据库字段名不一致问题
    Vue路由的使用简单实例
  • 原文地址:https://www.cnblogs.com/Anita9002/p/7150479.html
Copyright © 2011-2022 走看看