在 HSV/HSB 中淡入更自然的彩虹光谱

发布于 2024-10-20 00:04:27 字数 491 浏览 8 评论 0原文

我正在尝试控制一些 RGB LED 并从红色渐变为紫色。我正在使用 HSV 到 RGB 转换,这样我就可以从色调 0 扫描到色调 300(超过该范围,它会返回到红色)。但我注意到的问题是,它似乎在光谱的青色和蓝色部分花费了太多时间。所以我查了一下 HSV 谱应该是什么样子,发现了这个L

在此处输入图像描述

我没有意识到超过一半的光谱位于绿色和蓝色之间。

但我真的希望它看起来更像这样:

在此处输入图像描述

与“标准”彩虹色。 我想象这最终会成为正常色调值的某种 s 曲线,但我不太确定如何计算该曲线。

一个在内部处理这个问题的实际 HSV 到 RGB 算法会很棒(实际上任何代码,尽管它是针对 Arduino 的),但即使只是解释我如何计算色调曲线,我也会非常感激。

I'm trying to control some RGB LEDs and fade from red to violet. I'm using an HSV to RGB conversion so that I can just sweep from hue 0 to hue 300 (beyond that it moves back towards red). The problem I noticed though is that it seems to spend far to much time in the cyan and blue section of the spectrum. So I looked up what the HSV spectrum is supposed to look like, and found thisL

enter image description here

I didn't realize that more than half the spectrum was spent between green and blue.

But I'd really like it to look much more like this:

enter image description here

With a nice even blend of that "standard" rainbow colors.
I'd imagine that this would end up being some sort of s-curve of the normal hue values, but am not really sure how to calculate that curve.

An actual HSV to RGB algorithm that handles this internally would be great (any code really, though it's for an Arduino) but even just an explanation of how I could calculate that hue curve would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

好听的两个字的网名 2024-10-27 00:04:27

FastLED 做了一个版本: https://github.com/FastLED/FastLED /wiki/FastLED-HSV-Colors

Fast LED HSV

HSLUV 是另一种选择:http:// /www.hsluv.org/。他们拥有多种不同语言的库。

HSLUV

另外,这是一个有趣的技术:https://www.shadertoy.com/view /4l2cDm

const float tau = acos(-1.)*2.;

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;

    vec3 rainbow = sqrt( //gamma
        sin( (uv.x+vec3(0,2,1)/3.)*tau ) * .5 + .5
    );

    fragColor.rgb = rainbow;
}

在此处输入图像描述

另请参阅:
https://en.wikipedia.org/wiki/Rainbow#Number_of_colours_in_spectrum_or_rainbow了解更多信息。

FastLED does a a version of this: https://github.com/FastLED/FastLED/wiki/FastLED-HSV-Colors

Fast LED HSV

HSLUV is another option: http://www.hsluv.org/. They have libraries in a bunch of different languages.

HSLUV

Also, this is an interesting technique: https://www.shadertoy.com/view/4l2cDm

const float tau = acos(-1.)*2.;

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;

    vec3 rainbow = sqrt( //gamma
        sin( (uv.x+vec3(0,2,1)/3.)*tau ) * .5 + .5
    );

    fragColor.rgb = rainbow;
}

enter image description here

Also see:
https://en.wikipedia.org/wiki/Rainbow#Number_of_colours_in_spectrum_or_rainbow for more info.

晚雾 2024-10-27 00:04:27

http://www.fourmilab.ch/documents/specrend/ 有相当详细的描述如何将波长转换为 CIE 分量(大致对应于您眼睛中三种锥体传感器的输出),然后如何将它们转换为 RGB 值(警告某些波长没有< /em> 典型 RGB 色域中的 RGB 等效项)。

或者:有各种“感知均匀的色彩空间”,如 CIE L*a*b* (参见例如 http:// /en.wikipedia.org/wiki/Lab_color_space);您可以选择其中之一,沿着连接该空间中的起始颜色和结束颜色的直线采取相同的步骤,然后转换为 RGB。

不过,对于您的应用程序来说,其中任何一个都可能太过分了,而且没有明显的理由说明它们应该比更简单和纯经验的东西更好(或任何更好)。那么为什么不执行以下操作:

  1. 选择开始和结束颜色。为简单起见,我们假设 HSV 空间中 S=1 且 V=1。把它们记下来。
  2. 沿着您发布的色调“光谱”查找,找到您认为在起点和终点之间大约中间的颜色。请记下这一点。
  3. 现在再次平分:在开始和中间之间以及中间和结束之间找到颜色。
  4. 再重复一次或两次,以便将色相划分为 8 或 16 个“感知上相等”的部分。
  5. 转换为 RGB,将它们放入查找表中,并在其间进行线性插值。
  6. 稍微调整 RGB 值,直到获得看起来不错的效果。

这完全是临时的,根本没有任何原则性,但它可能会工作得很好,并且最终的代码基本上很简单:(

void compute_rgb(int * rp, int * gp, int * bp, int t) {
  // t in the range 0..255 (for convenience)
  int segment = t>>5; // 0..7
  int delta = t&31;
  int a=rgb_table[segment].r, b=rgb_table[segment+1].r;
  *rp = a + ((delta*(b-a))>>5);
  a=rgb_table[segment].g; b=rgb_table[segment+1].g;
  *gp = a + ((delta*(b-a))>>5);
  a=rgb_table[segment].b; b=rgb_table[segment+1].b;
  *bp = a + ((delta*(b-a))>>5);
}

如果您不关心保存每个可用周期,则可以使代码更清晰)。

无论如何,我的眼睛将划分点设置为大约 (0)、40、60、90、150、180、240、270、(300) 的色调值。您的里程可能会有所不同。

http://www.fourmilab.ch/documents/specrend/ has a fairly detailed description of how to convert a wavelength to CIE components (which roughly correspond to the outputs of the three kinds of cone sensors in your eyes) and then how to convert those to RGB values (with a warning that some wavelengths don't have RGB equivalents in a typical RGB gamut).

Or: there are various "perceptually uniform colour spaces" like CIE L*a*b* (see e.g. http://en.wikipedia.org/wiki/Lab_color_space); you could pick one of those, take equal steps along a straight line joining your starting and ending colours in that space, and convert to RGB.

Either of those is likely to be overkill for your application, though, and there's no obvious reason why they should be much -- or any -- better than something simpler and purely empirical. So why not do the following:

  1. Choose your starting and ending colours. For simplicity, let's suppose they have S=1 and V=1 in HSV space. Note them down.
  2. Look along the hue "spectrum" that you posted and find a colour that looks to you about halfway between your starting and ending points. Note this down.
  3. Now bisect again: find colours halfway between start and mid, and halfway between mid and end.
  4. Repeat once or twice more, so that you've divided the hue scale into 8 or 16 "perceptually equal" parts.
  5. Convert to RGB, stick them in a lookup table, and interpolate linearly in between.
  6. Tweak the RGB values a bit until you have something that looks good.

This is totally ad hoc and has nothing principled about it at all, but it'll probably work pretty well and the final code will be basically trivial:

void compute_rgb(int * rp, int * gp, int * bp, int t) {
  // t in the range 0..255 (for convenience)
  int segment = t>>5; // 0..7
  int delta = t&31;
  int a=rgb_table[segment].r, b=rgb_table[segment+1].r;
  *rp = a + ((delta*(b-a))>>5);
  a=rgb_table[segment].g; b=rgb_table[segment+1].g;
  *gp = a + ((delta*(b-a))>>5);
  a=rgb_table[segment].b; b=rgb_table[segment+1].b;
  *bp = a + ((delta*(b-a))>>5);
}

(you can make the code somewhat clearer if you don't care about saving every available cycle).

For what it's worth, my eyes put division points at hue values of about (0), 40, 60, 90, 150, 180, 240, 270, (300). Your mileage may vary.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文