« 乱弹OpenGL选择-拾取机制(下)圆心坐标的提取 »

图像色彩空间与HSL/HSV

 我们用RGBA来描述一个像素的颜色,没错,这对计算机来说最方便不过?不过除了RGB,你还听说过HSL/HSV吗?——ZwqXin.com

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

其实不只HSL/HSV,还有什么CMYK啊,LAB啊的,都是采用不同的标准去描述颜色。人所见到的颜色是有限界的,因此真实的颜色永远不会被穷举完成;同时,人所能感受的颜色差别更是有限,因此就有了有限的表示法。


CIE 1931 色彩空间,最先采用数学方式来定义的色彩空间,基于人类颜色视觉的直接测定。由国际照明委员会(CIE)于1931年创立)

sRGB色彩空间是美国的惠普公司和微软公司于1997年共同开发的标准色彩空间(standard Red Green Blue),AdobeRGB色彩空间是由美国以开发Photoshop软件而闻名的Adobe公司1998年推出的色彩空间标准,但是它们都远远没能包含整个CIE 1931色彩空间(基于人类颜色视觉的直接测定,包含人类所感知的最丰富色表),可见计算机在颜色表现这块上的局限性。

色彩空间,是一种对颜色的描述方法,依照其描述方法而形成一个装载颜色的容器。譬如最常用的RGB法,把颜色分到红绿蓝三通道,是一种非线性的描述方式;LAB中,L 表示亮度,ab 表示颜色对立维度,是一种感知线性的描述方式。前者(以及HSL/HSV等)依赖于具体设备,后者(以及CMYK等)则独立于设备,因此前者和后者不可以简单地相互转换,需要通过中间媒介(sRGB或AdobeRGB这种一定独立设备的设备内描述方式)进行转换。

而这次实现的RGB到HSL/HSV空间的转换,和HSL/HSV到RGB的转换,则没有那么麻烦,它们都是设备相关的非线性颜色描述方式。HSL表示 hue(色相)、saturation(饱和度)、lightness(亮度),HSV 表示 hue(色相)、 saturation(饱和度)、value (值)。它们俩是很类似的,但又有定义上的不同,其中,前者的饱和度和后者的饱和度不是同一个定义恩。

相关的转换公式可以参考[HSL和HSV色彩空间 - 维基百科],这里以HSL和RGB互转为例,转化为代码:

  1. void FormatHSLConvert::RGBToHSLConvert(FilterColor oColor, FilterColor& rColor)
  2. {
  3.         UCHAR MaxCol = oColor.red;
  4.         UCHAR MinCol = oColor.red;          
  5.  
  6.         if(oColor.green > MaxCol)
  7.               MaxCol = oColor.green;
  8.         else
  9.               MinCol = oColor.green;
  10.         
  11.         if(oColor.blue > MaxCol)
  12.               MaxCol = oColor.blue;
  13.         if(oColor.blue < MinCol)
  14.               MinCol = oColor.blue;
  15.  
  16.         double Hue = 0.0; //色相 (0-360)
  17.         double saturation = 0.0; //饱和度 (0,1)
  18.         double lightness = 0.0;  //亮度 (0,1)
  19.  
  20.         if(CurrentHSLChannel == HCHannelHSL || CurrentHSLChannel == HSLCHannelHSL)
  21.         {
  22.         if(MaxCol == MinCol)
  23.             Hue = 0;
  24.         else 
  25.             if(MaxCol == oColor.red && oColor.green >= oColor.blue)
  26.               Hue = 60.0 * double(oColor.green - oColor.blue) / (MaxCol - MinCol);
  27.         else 
  28.             if(MaxCol == oColor.red && oColor.green < oColor.blue)
  29.               Hue = 60.0 * double(oColor.green - oColor.blue) / (MaxCol - MinCol) + 360;
  30.         else 
  31.             if(MaxCol == oColor.green)
  32.               Hue = 60.0 * double(oColor.blue - oColor.red) / (MaxCol - MinCol) + 120;
  33.         else 
  34.             if(MaxCol == oColor.blue)
  35.               Hue = 60.0 * double(oColor.red - oColor.green) / (MaxCol - MinCol) + 240;
  36.         }
  37.  
  38.         if(CurrentHSLChannel == LCHannelHSL || CurrentHSLChannel == SCHannelHSL 
  39.                      || CurrentHSLChannel == HSLCHannelHSL)
  40.         {
  41.            lightness = ((double)MaxCol/255 + (double)MinCol/255) / 2;
  42.         }
  43.  
  44.         if(CurrentHSLChannel == SCHannelHSL || CurrentHSLChannel == HSLCHannelHSL)
  45.         {
  46.            if(lightness == 0 || MaxCol == MinCol)
  47.               saturation = 0.0;
  48.            else if(lightness <= 0.5 && lightness > 0)
  49.               saturation = double(MaxCol - MinCol) / (MaxCol + MinCol);
  50.            else if(lightness > 0.5)
  51.               saturation = double(MaxCol - MinCol) / ( 510 - (MaxCol + MinCol));
  52.         }
  53.  
  54.       if(CurrentHSLChannel == HSLCHannelHSL)
  55.       {
  56.        rColor.red   = Hue / 360.0 * 255 + VariedHue;
  57.        rColor.green = saturation * 255 + VariedSaturation;  
  58.        rColor.blue  = lightness * 255 + VariedLightness;
  59.       }
  60.       else
  61.       { 
  62.           int Col;
  63.           if(CurrentHSLChannel == HCHannelHSL)
  64.               Col = Hue / 360.0 * 255 + VariedHue;
  65.           else 
  66.               if(CurrentHSLChannel == SCHannelHSL)
  67.               Col = saturation * 255 + VariedSaturation;
  68.           else 
  69.               if(CurrentHSLChannel == LCHannelHSL)
  70.               Col = lightness * 255 + VariedLightness;
  71.  
  72.           rColor.set(Col, Col, Col);
  73.       }
  74.  
  75.      rColor.SetRange(0, 255);
  76. }
  77.  
  78. void FormatHSLConvert::HSLToRGBConvert(FilterColor oColor, FilterColor& rColor)
  79. {
  80.     //oColor.red   - oColor.Hue
  81.     //oColor.green - oColor.saturation
  82.     //oColor.blue  - oColor.lightness
  83.  
  84.     if(oColor.green == 0)
  85.          rColor.set(oColor.blue, oColor.blue, oColor.blue);
  86.     else
  87.     {   
  88.         double Hue        = (double)oColor.red / 255.0; //色相 (原0-360,规范化到0 -1 )
  89.         double saturation = (double)oColor.green / 255.0; //饱和度 (0,1)
  90.         double lightness  = (double)oColor.blue / 255.0;  //亮度 (0,1)
  91.  
  92.         double mp = 0.0, mq = 0.0;
  93.         double tRGB[3];
  94.         int i = 0;
  95.  
  96.         if(lightness < 0.5)
  97.           mq = lightness * (1 + saturation);
  98.         else
  99.           mq = lightness + saturation - (lightness * saturation);
  100.  
  101.         mp = 2 * lightness - mq;
  102.  
  103.         tRGB[0] = Hue + 0.333333;  // tR
  104.         tRGB[1] = Hue;             // tG
  105.         tRGB[2] = Hue - 0.333333;  // tB
  106.  
  107.         for(i = 0; i < 3; ++i)
  108.         {
  109.         if(tRGB[i] < 0)
  110.             tRGB[i] = tRGB[i] + 1.0;
  111.         else if(tRGB[i] > 1)
  112.             tRGB[i] = tRGB[i] - 1.0;
  113.  
  114.         if(tRGB[i] < 0.166666)
  115.             tRGB[i] = mp + ((mq - mp) * 6 * tRGB[i]);
  116.         else if(tRGB[i] >= 0.166666 && tRGB[i] < 0.5)
  117.             tRGB[i] = mq;
  118.         else if(tRGB[i] >= 0.5 && tRGB[i] < 0.666666)
  119.             tRGB[i] = mp + ((mq - mp) * 6 * (0.666666 - tRGB[i]));
  120.         else
  121.             tRGB[i] = mp;
  122.         }
  123.  
  124.         rColor.set(tRGB[0]* 255, tRGB[1]* 255, tRGB[2]* 255);
  125.         rColor.SetRange(0, 255);
  126.     }
  127.  
  128. }

说到底,转换的原理,那些深奥的东西我们没有必要知道,只要知道具体的转换公式,一切都很简单了。

程序截图:
[若看不到本博客图片,可参照此帖,简单的复原法:[显示本站所有图片] ]

图像空间HSL/HSV  www.zwqxin.com
(原图片)

 HSL/HSV空间 [FormatHSLConvert & FormatHSVConvert]
[注:以下展示,为在HSL空间里修改参量,在RGB空间里查看结果]
图像空间HSL/HSV  www.zwqxin.com
(在HSL空间,单独提高色相H分量)
图像空间HSL/HSV  www.zwqxin.com
(在HSL空间,单独提高饱和度S分量)
图像空间HSL/HSV  www.zwqxin.com
(在HSL空间,单独提高亮度L分量)
图像空间HSL/HSV  www.zwqxin.com
[当然可随意自由转换空间,如上为保持HSL空间的修改回到RGB空间,查看R/G分量]
[注:以下展示,为在HSV空间里修改参量,在RGB空间里查看结果]
图像空间HSL/HSV  www.zwqxin.com
(在HSV空间,单独降低色相H分量)
图像空间HSL/HSV  www.zwqxin.com
(在HSV空间,单独降低饱和度S分量[注意此S不同上S])
图像空间HSL/HSV  www.zwqxin.com
(在HSV空间,单独降低“值”V分量)
图像空间HSL/HSV  www.zwqxin.com
[当然可随意在任何空间查看谱图或单独查看某一分量谱图,如上为HSV空间和HSV空间的S分量查看图(按灰度展示)]

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

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

IE下本页面显示有问题?

→点击地址栏右侧【兼容视图】←

日历

Search

网站分类

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Walle Build 100427

Copyright 2008-2013 ZwqXin. All Rights Reserved. Theme edited from ipati.