HSV色彩属性模式是根据色彩的三个基本属性:色相、饱和度和明度来
确定颜
色的一种方法。
- 色相(H)是色彩的基本属性,就是平常所说的颜色名
称,如红
色、黄色等,依照在右图的标准色轮上的位置,取0-360度的数值。(也有用0 –100%的方法确定的)。
- 饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。
- 明度(V)也叫“亮度”,取0-100%。
这种模式是 1978年 由 Alvy Ray Smith 创立的,它是三原色光模式的一种非线性变换。
算法核心是这样的
Vector3f HSV2RGB(const Vector3f& hsv)
{
//先根据Hue计算出一个"纯的亮的颜色"
Vector3f hueColor =
GetColorByHue(hsv.h);
//然后用Sat和Value做两次线性插值,Sat越高颜色越纯,越低会使颜色越靠近灰色,Value控制亮度。
return lerp<Vector3f>(0,
lerp<Vector3f>(1, hueColor, hsv.s), hsv.v);
}
// hue应该是属于[0,1),但有时也认为属于[0,1]
// 其实影响不大,我这里统一处理了
Vector3f GetColorByHue(float hue)
{
Vector3f color;
hue = max(0.0f, min(hue, 1.0f));
float hue6 = hue*6.0f;
int z = min((int)hue6, 5);
float f = hue6 - z;
//可以想象一个圆,hue值与圆周上的点一一对应
//圆周被均分成6段,每段只引起一个RGB分量变化
switch(int(hue*6.0f))
{
case 0:
color.r = 1.0f;
color.g = f;
color.b = 0.0f;
break;
case 1:
color.r = 1.0f - f;
color.g = 1.0f;
color.b = 0.0f;
break;
case 2:
color.r = 0.0f;
color.g = 1.0f;
color.b = f;
break;
case 3:
color.r = 0.0f;
color.g = 1.0f - f;
color.b = 1.0f;
break;
case 4:
color.r = f;
color.g = 0.0f;
color.b = 1.0f;
break;
case 5:
default:
color.r = 1.0f;
color.g = 0.0f;
color.b = 1.0f - f;
}
return color;
}
#include <iostream>
#include <cmath>
using namespace std;
struct Vector3f
{
Vector3f(){}
Vector3f(const Vector3f& v):x(v.x),y(v.y),z(v.z){}
Vector3f(float f):x(f),y(f),z(f){}
Vector3f(float x,float y,float z):x(x),y(y),z(z){}
Vector3f operator + (const Vector3f& v) const
{
return Vector3f(x+v.x, y+v.y, z+v.z);
}
Vector3f operator - (const Vector3f& v) const
{
return Vector3f(x-v.x, y-v.y, z-v.z);
}
Vector3f operator * (const Vector3f& v) const
{
return Vector3f(x*v.x, y*v.y, z*v.z);
}
Vector3f operator / (const Vector3f& v) const
{
return Vector3f(x/v.x, y/v.y, z/v.z);
}
union{
struct{float x,y,z;};
struct{float r,g,b;};
struct{float h,s,v;};
};
};
Vector3f operator + (float f, const Vector3f& v){ return Vector3f(f+v.x, f+v.y, f+v.z);}
Vector3f operator - (float f, const Vector3f& v){ return Vector3f(f-v.x, f-v.y, f-v.z);}
Vector3f operator * (float f, const Vector3f& v){ return Vector3f(f*v.x, f*v.y, f*v.z);}
Vector3f operator / (float f, const Vector3f& v){ return Vector3f(f/v.x, f/v.y, f/v.z);}
template <typename T>
T lerp(const T& x, const T& y, const T& s)
{
return x*(1-s) + y*s;
}
// hue应该是属于[0,1),但有时也认为属于[0,1]
// 其实影响不大,我这里统一处理了
Vector3f GetColorByHue(float hue)
{
Vector3f color;
hue = max(0.0f, min(hue, 1.0f));
float hue6 = hue*6.0f;
int z = min((int)hue6, 5);
float f = hue6 - z;
//可以想象一个圆,hue与圆周上的点一一对应
//圆周被均分成6段,每段只引起一个RGB分量变化
switch(int(hue*6.0f))
{
case 0:
color.r = 1.0f;
color.g = f;
color.b = 0.0f;
break;
case 1:
color.r = 1.0f - f;
color.g = 1.0f;
color.b = 0.0f;
break;
case 2:
color.r = 0.0f;
color.g = 1.0f;
color.b = f;
break;
case 3:
color.r = 0.0f;
color.g = 1.0f - f;
color.b = 1.0f;
break;
case 4:
color.r = f;
color.g = 0.0f;
color.b = 1.0f;
break;
case 5:
default:
color.r = 1.0f;
color.g = 0.0f;
color.b = 1.0f - f;
}
return color;
}
Vector3f HSV2RGB(const Vector3f& hsv)
{
Vector3f hueColor = GetColorByHue(hsv.h);
return hsv.v * lerp<Vector3f>(1, hueColor, hsv.s);
//return lerp<Vector3f>(0, lerp<Vector3f>(1, hueColor, hsv.s), hsv.v);
}
int main()
{
printf("HSV<360,256,256>->RGB<256,256,256>\n");
int h,s,v;
while(scanf("%d%d%d", &h, &s, &v)!=EOF)
{
Vector3f hsv = Vector3f(h/360.0f,s/256.0f,v/256.f);
Vector3f rgb = HSV2RGB(hsv);
printf("RGB(%d,%d,%d)\n", (int)(rgb.r*256), (int)(rgb.g*256), (int)(rgb.b*256));
}
}