beat365网址官网网站-365体育世界杯专用版-365体育注册送365

HSV/HSB/HSL 色相、饱和度、亮度的色彩模型

HSV/HSB/HSL 色相、饱和度、亮度的色彩模型

文章目录

什么是HSV/HSB/HSLHue 色相Saturation饱和度Value 亮度互转公式RGB to HSV 公式HSV to RGB 公式RGB to HSV & HSV to RGBRGB to HSV ver1.0RGB2HSV & HSV2RGB

使用C# WinForm写了个DemoProject

References

什么是HSV/HSB/HSL

首先理解 HSV/HSB/HSL 都是什么

我理解:

HSV : Hue, Saturation, ValueHSB : Hue, Saturation, BrightnessHSL : Hue, Saturation, Lightness(或是Luminance)

Hue : 色相 Saturation: 饱和度 其中的Value、Brightness、Lightness都是用于控制亮度用的

三者同一个意思,就是叫法不一 下面使用HSV的方式来介绍

看一张图:

下面是我看到这张图,然后对HSV的理解

Hue 色相

从上图可以看出:Hue就是颜色的周期

逆时针一圈可以看出过渡规律: R~RG~G~GB~B~RB~R 后面~R可以可以省略,因为可以倒回开头的R 如下: R~RG~G~GB~B~RB~R ⇒ R~RG~G~GB~B~RB (红~黄~绿~浅蓝~蓝~粉紫(倒回~红))

而这些过渡,对应的是:Hue的0~360的6个区间,如下伪代码,对应的是:Hue 与 RGB 的映射

// jave.lin 2019.09.03

// Hue to RGB

oneRegion = 360f/6; // 或是1f/6

region1 = onRegion;

region2 = onRegion * 2;

region3 = onRegion * 3;

region4 = onRegion * 4;

region5 = onRegion * 5;

region6 = onRegion * 6;

if (position >= region1 && position < region2) {

// R~RG

} else if (position >= region2 && position < region3) {

// RG~G

} else if (position >= region3 && position < region4) {

// G~GB

} else if (position >= region4 && position < region5) {

// GB~B

} else if (position >= region5 && position < region6) {

// B~RB

}

Saturation饱和度

从上图可以看出来,就是颜色鲜艳度,就是对应白色到Hue色之间的过渡关系,Saturation越大越偏向于Hue色,否则偏向于白色

也可以理解为颜色的鲜艳度,饱和度高,越鲜艳,饱和度底,越灰白

对应伪代码就是:

// jave.lin 2019.09.03

// Saturation理解

float t = 0f~1f; // 或是0~100,用于控制饱和度强度

Color whiteColor = Color.white;

Color hueColor = ...; // 就是先从上面的hue中确定色相

Color FinalColor = Lerp(whiteColor, hueColor, t); // Lerp(a,b,t) => a*(1-t)+b*t,下面用到的Lerp都是一样的

Value 亮度

从上图可以看出,Value就是控制亮度的,Value值越小,越偏向黑色,否则偏向Hue色相应用Saturation后的颜色

伪代码:

// jave.lin 2019.09.03

// Value 理解

float t = 0f~1f; // 或是0~100,用于控制亮度强度

Color saturateColor = Lerp(whiteColor, hueColor, saturateT); // 上面Saturate的值

Color blackColor = Color.black;

Color FinalColor = Lerp(blackColor, saturateColor, t);

互转公式

除了上面我们自己总结的规律,下面是引用了别的博主的内容,参考:Unity Shader-后处理:简单的颜色调整(亮度,饱和度,对比度)

RGB to HSV 公式

HSV to RGB 公式

你也可以自己去编写相关的逻辑。

然后我最近有在学习Unity,与UnityShader相关的内容,里面有部分shader代码是有应用这些公式的,源码如下:

RGB to HSV & HSV to RGB

这个是没有考虑分量大小直接转换的:

#if defined(_COLORCOLOR_ON)

half3 RGBtoHSV(half3 arg1)

{

half4 K = half4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);

half4 P = lerp(half4(arg1.bg, K.wz), half4(arg1.gb, K.xy), step(arg1.b, arg1.g));

half4 Q = lerp(half4(P.xyw, arg1.r), half4(arg1.r, P.yzx), step(P.x, arg1.r));

half D = Q.x - min(Q.w, Q.y);

half E = 1e-10;

return half3(abs(Q.z + (Q.w - Q.y) / (6.0 * D + E)), D / (Q.x + E), Q.x);

}

half3 HSVtoRGB(half3 arg1)

{

half4 K = half4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);

half3 P = abs(frac(arg1.xxx + K.xyz) * 6.0 - K.www);

return arg1.z * lerp(K.xxx, saturate(P - K.xxx), arg1.y);

}

#endif

RGB to HSV ver1.0

这种是有考虑RGB分量那个比较高的分支处理。

half3 UnityMeta_RGBToHSVHelper(float offset, half dominantColor, half colorone, half colortwo)

{

half H, S, V;

V = dominantColor;

if (V != 0.0)

{

half small = 0.0;

if (colorone > colortwo)

small = colortwo;

else

small = colorone;

half diff = V - small;

if (diff != 0)

{

S = diff / V;

H = offset + ((colorone - colortwo)/diff);

}

else

{

S = 0;

H = offset + (colorone - colortwo);

}

H /= 6.0;

if (H < 6.0)

{

H += 1.0;

}

}

else

{

S = 0;

H = 0;

}

return half3(H, S, V);

}

half3 UnityMeta_RGBToHSV(half3 rgbColor)

{

// when blue is highest valued

if((rgbColor.b > rgbColor.g) && (rgbColor.b > rgbColor.r))

return UnityMeta_RGBToHSVHelper(4.0, rgbColor.b, rgbColor.r, rgbColor.g);

//when green is highest valued

else if(rgbColor.g > rgbColor.r)

return UnityMeta_RGBToHSVHelper(2.0, rgbColor.g, rgbColor.b, rgbColor.r);

//when red is highest valued

else

return UnityMeta_RGBToHSVHelper(0.0, rgbColor.r, rgbColor.g, rgbColor.b);

}

RGB2HSV & HSV2RGB

//================================================================

// HSV HELPERS

// source: http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl

float3 rgb2hsv(float3 c)

{

float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);

float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));

float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));

float d = q.x - min(q.w, q.y);

float e = 1.0e-10;

return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);

}

float3 hsv2rgb(float3 c)

{

c.g = max(c.g, 0.0); //make sure that saturation value is positive

float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);

float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);

return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);

}

使用C# WinForm写了个Demo

下面是使用了最初我们总结的规律逻辑来写的(没使用公式)。

主要以:Graphics类、与Bitmap来实现, Graphics.DrawImage(Image image); 圈圈、线条都是直接Graphics.DrawLine, Graphics.DrawEllipse 主要核心代码:

// t : [0~1]对应:0~360

// 返回的颜色

private void GetH(float t, out byte r, out byte g, out byte b)

{

r = 0; g = 0; b = 0;

const float t1 = 1f / 6;

const float t2 = 1f / 6 * 2;

const float t3 = 1f / 6 * 3;

const float t4 = 1f / 6 * 4;

const float t5 = 1f / 6 * 5;

const float t6 = 1f / 6 * 6;

const float invOne = 6f;

t = t < 0 ? 0 : t;

t = t > 1 ? 1 : t;

if (t >= 0 && t < t1)

{

// R ~ RG

r = 255;

g = (byte)(t * invOne * 255);

b = 0;

}

else if (t >= t1 && t < t2)

{

// RG ~ G

r = (byte)((1 - (t - t1) * invOne) * 255);

g = 255;

b = 0;

}

else if (t >= t2 && t < t3)

{

// G ~ GB

r = 0;

g = 255;

b = (byte)((t - t2) * invOne * 255);

}

else if (t >= t3 && t < t4)

{

// GB ~ B

r = 0;

g = (byte)((1 - (t - t3) * invOne) * 255);

b = 255;

}

else if (t >= t4 && t < t5)

{

// B ~ RB

r = (byte)((t - t4) * invOne * 255);

g = 0;

b = 255;

}

else if (t >= t5 && t <= t6)

{

// RB ~ R

r = 255;

g = 0;

b = (byte)((1 - (t - t5) * invOne) * 255);

}

}

private void GetSV(

// tr,tg,tb 目标颜色

byte tr, byte tg, byte tb,

// st 饱和度插值系数

// vt 亮度插值系数

float st, float vt,

// 输出的 rgb 颜色

out byte r, out byte g, out byte b)

{

float stt = 1 - st;

float vtt = 1 - vt;

// 饱和度

tb = Lerp(255, tb, st, stt);

tg = Lerp(255, tg, st, stt);

tr = Lerp(255, tr, st, stt);

// 亮度

b = Lerp(tb, 0, vt, vtt);

g = Lerp(tg, 0, vt, vtt);

r = Lerp(tr, 0, vt, vtt);

}

Project

Test_HSV_HSB_HSL_色相_饱和度_亮度.zip

References

Unity Shader-后处理:简单的颜色调整(亮度,饱和度,对比度)彩色图像和颜色空间