登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

易拉罐的博客

心静自然凉

 
 
 

日志

 
 

转 图像色彩空间与HSL/HSV  

2010-04-08 22:19:18|  分类: 机器视觉 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |


我们用RGBA来描述一个像素的颜色,没错,这对计算机来说最方便不过?不过除了RGB,你还听说过HSL/HSV吗?——ZwqXin.com
其实不只HSL/HSV,还有什么CMYK啊,LAB啊的,都是采用不同的标准去描述颜色。人所见到的颜色是有限界的,因此真实的颜色永远不会被穷举完成;同时,人所能感受的颜色差别更是有限,因此就有了有限的表示法。

转 图像色彩空间与HSL/HSV - 易拉罐bb - 易拉罐的博客

(CIE 1931 色彩空间,最先采用数学方式来定义的色彩空间,基于人类颜色视觉的直接测定。由国际照明委员会(CIE)于1931年创立)
sRGB色彩空间是美国的惠普公司和微软公司于1997年共同开发的标准色彩空间(standard Red Green Blue),AdobeRGB色彩空间是由美国以开发Photoshop软件而闻名的Adobe公司1998年推出的色彩空间标准,但是它们都远远没能包含整个CIE 1931色彩空间(基于人类颜色视觉的直接测定,包含人类所感知的最丰富色表),可见计算机在颜色表现这块上的局限性。
色彩空间,是一种对颜色的描述方法,依照其描述方法而形成一个装载颜色的容器。譬如最常用的RGB法,把颜色分到红绿蓝三通道,是一种非线性的描述方式;LAB中,L 表示亮度,a 和 b 表示颜色对立维度,是一种感知线性的描述方式。前者(以及HSL/HSV等)依赖于具体设备,后者(以及CMYK等)则独立于设备,因此前者和后者不可以简单地相互转换,需要通过中间媒介(sRGB或AdobeRGB这种一定独立设备的设备内描述方式)进行转换。
而这次实现的RGB到HSL/HSV空间的转换,和HSL/HSV到RGB的转换,则没有那么麻烦,它们都是设备相关的非线性颜色描述方式。HSL表示 hue(色相)、saturation(饱和度)、lightness(亮度),HSV 表示 hue(色相)、 saturation(饱和度)、value (值)。它们俩是很类似的,但又有定义上的不同,其中,前者的饱和度和后者的饱和度不是同一个定义恩。
相关的转换公式可以参考[HSL和HSV色彩空间 - 维基百科],这里以HSL和RGB互转为例,转化为代码:
 
void FormatHSLConvert::RGBToHSLConvert(FilterColor oColor, FilterColor& rColor)
{
        UCHAR MaxCol = oColor.red;
        UCHAR MinCol = oColor.red;          
 
        if(oColor.green > MaxCol)
              MaxCol = oColor.green;
        else
              MinCol = oColor.green;
        
        if(oColor.blue > MaxCol)
              MaxCol = oColor.blue;
        if(oColor.blue < MinCol)
              MinCol = oColor.blue;
 
        double Hue = 0.0; //色相 (0-360)
        double saturation = 0.0; //饱和度 (0,1)
        double lightness = 0.0;  //亮度 (0,1)
 
        if(CurrentHSLChannel == HCHannelHSL || CurrentHSLChannel == HSLCHannelHSL)
        {
        if(MaxCol == MinCol)
            Hue = 0;
        else 
            if(MaxCol == oColor.red && oColor.green >= oColor.blue)
              Hue = 60.0 * double(oColor.green - oColor.blue) / (MaxCol - MinCol);
        else 
            if(MaxCol == oColor.red && oColor.green < oColor.blue)
              Hue = 60.0 * double(oColor.green - oColor.blue) / (MaxCol - MinCol) + 360;
        else 
            if(MaxCol == oColor.green)
              Hue = 60.0 * double(oColor.blue - oColor.red) / (MaxCol - MinCol) + 120;
        else 
            if(MaxCol == oColor.blue)
              Hue = 60.0 * double(oColor.red - oColor.green) / (MaxCol - MinCol) + 240;
        }
 
        if(CurrentHSLChannel == LCHannelHSL || CurrentHSLChannel == SCHannelHSL 
                     || CurrentHSLChannel == HSLCHannelHSL)
        {
           lightness = ((double)MaxCol/255 + (double)MinCol/255) / 2;
        }
 
        if(CurrentHSLChannel == SCHannelHSL || CurrentHSLChannel == HSLCHannelHSL)
        {
           if(lightness == 0 || MaxCol == MinCol)
              saturation = 0.0;
           else if(lightness <= 0.5 && lightness > 0)
              saturation = double(MaxCol - MinCol) / (MaxCol + MinCol);
           else if(lightness > 0.5)
              saturation = double(MaxCol - MinCol) / ( 510 - (MaxCol + MinCol));
        }
 
      if(CurrentHSLChannel == HSLCHannelHSL)
      {
       rColor.red   = Hue / 360.0 * 255 + VariedHue;
       rColor.green = saturation * 255 + VariedSaturation;  
       rColor.blue  = lightness * 255 + VariedLightness;
      }
      else
      { 
          int Col;
          if(CurrentHSLChannel == HCHannelHSL)
              Col = Hue / 360.0 * 255 + VariedHue;
          else 
              if(CurrentHSLChannel == SCHannelHSL)
              Col = saturation * 255 + VariedSaturation;
          else 
              if(CurrentHSLChannel == LCHannelHSL)
              Col = lightness * 255 + VariedLightness;
 
          rColor.set(Col, Col, Col);
      }
 
     rColor.SetRange(0, 255);
}
 
void FormatHSLConvert::HSLToRGBConvert(FilterColor oColor, FilterColor& rColor)
{
    //oColor.red   - oColor.Hue
    //oColor.green - oColor.saturation
    //oColor.blue  - oColor.lightness
 
    if(oColor.green == 0)
         rColor.set(oColor.blue, oColor.blue, oColor.blue);
    else
    {   
        double Hue        = (double)oColor.red / 255.0; //色相 (原0-360,规范化到0 -1 )
        double saturation = (double)oColor.green / 255.0; //饱和度 (0,1)
        double lightness  = (double)oColor.blue / 255.0;  //亮度 (0,1)
 
        double mp = 0.0, mq = 0.0;
        double tRGB[3];
        int i = 0;
 
        if(lightness < 0.5)
          mq = lightness * (1 + saturation);
        else
          mq = lightness + saturation - (lightness * saturation);
 
        mp = 2 * lightness - mq;
 
        tRGB[0] = Hue + 0.333333;  // tR
        tRGB[1] = Hue;             // tG
        tRGB[2] = Hue - 0.333333;  // tB
 
        for(i = 0; i < 3; ++i)
        {
        if(tRGB[i] < 0)
            tRGB[i] = tRGB[i] + 1.0;
        else if(tRGB[i] > 1)
            tRGB[i] = tRGB[i] - 1.0;
 
        if(tRGB[i] < 0.166666)
            tRGB[i] = mp + ((mq - mp) * 6 * tRGB[i]);
        else if(tRGB[i] >= 0.166666 && tRGB[i] < 0.5)
            tRGB[i] = mq;
        else if(tRGB[i] >= 0.5 && tRGB[i] < 0.666666)
            tRGB[i] = mp + ((mq - mp) * 6 * (0.666666 - tRGB[i]));
        else
            tRGB[i] = mp;
        }
 
        rColor.set(tRGB[0]* 255, tRGB[1]* 255, tRGB[2]* 255);
        rColor.SetRange(0, 255);
    }
 
}
说到底,转换的原理,那些深奥的东西我们没有必要知道,只要知道具体的转换公式,一切都很简单了。
程序截图:

本文来源于ZwqXin http://www.zwqxin.com/ , 转载请注明
原文地址:http://www.zwqxin.com/archives/image-processing/image-hsl-hsv.html

  评论这张
 
阅读(1191)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018