【问题标题】:Fade through more more natural rainbow spectrum in HSV/HSB在 HSV/HSB 中淡出更自然的彩虹光谱
【发布时间】:2011-03-02 01:31:54
【问题描述】:

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

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

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

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

在内部处理此问题的实际 HSV 到 RGB 算法会很棒(任何代码,虽然它是针对 Arduino 的),但即使只是解释我如何计算色调曲线也将不胜感激。

【问题讨论】:

    标签: colors rgb hsv


    【解决方案1】:

    http://www.fourmilab.ch/documents/specrend/ 相当详细地描述了如何将波长转换为 CIE 分量(大致对应于您眼中的三种锥形传感器的输出),然后如何将其转换为 RGB 值(使用警告某些波长在典型的 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) 的色调值上。您的里程可能会有所不同。

    【讨论】:

      【解决方案2】:

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

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

      另外,这是一个有趣的技术: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 了解更多信息。

      【讨论】:

        猜你喜欢
        • 2015-10-04
        • 2013-03-18
        • 2015-11-16
        • 1970-01-01
        • 2016-05-08
        • 1970-01-01
        • 2012-07-24
        • 2011-03-26
        • 2015-03-11
        相关资源
        最近更新 更多