【问题标题】:Paint me a Rainbow给我画彩虹
【发布时间】:2010-11-15 18:01:43
【问题描述】:

您将如何使一系列 RGB 颜色在光谱颜色范围内均匀分布?这样才能看起来像真正的彩虹。

【问题讨论】:

    标签: language-agnostic colors rgb


    【解决方案1】:

    其他解决方案需要相当大量的代码和条件分支,这使得它们不适合 GPU。我最近在 GLSL 中找到了以下神奇的简单公式。在 OpenCL 中基本相同:

    vec3 HueToRGB(float hue) {
      vec3 h = vec3(hue, hue + 1.0/3.0, hue + 2.0/3.0);
      return clamp(6.0 * abs(h - floor(h) - 0.5) - 1.0, 0.0, 1.0);
    }
    

    这将为您提供与线性 RGB 中给定色调值相对应的彩虹色。要在图像中使用,请转换为 sRGB,然后乘以 255。

    这是一个 C++17 版本:

    std::array<float, 3> HueToRGB(float hue, float *rgb) {
      std::array<float, 3> rgb;
      for (unsigned i = 0; i < 3; ++i) {
        const float h = hue + i / 3.f;
        rgb[i] = std::clamp(6.f * std::fabs(h - std::floor(h) - 0.5f) - 1.f, 0.f, 1.f);
      }
      return rgb;
    }
    

    这里的关键是要意识到,R、G、B坐标中的每一个在色调值的函数中的图形是一个周期三角函数的一个钳位值,并且可以得到一个锯齿的绝对值函数,x - floor(x)

    【讨论】:

      【解决方案2】:

      我知道这是一个相当老的问题,但这是我的简单易懂的解决方案,在大多数编程语言中应该很容易使用。 将步骤和 whichStep 替换为您自己的值。

      int steps = 1280;
      int stepChange = 1280 / steps;
      int change = stepChange * whichStep;
      int r=0, g=0, b=0;
      
      if (change < 256)
      {
          r = 255;
          g += change;
      }
      else if (change < 512)
      {
          r = 511 - change;
          g = 255;
      }
      else if (change < 768)
      {
          g = 255;
          b = change-512;
      }
      else if (change < 1024)
      {
          g = 1023 - change;
          b = 255;
      }
      else
      {
          r = change - 1024;
          b = 255;
      }
      

      【讨论】:

        【解决方案3】:

        我可以使用 JavaScript 和 HTML5 以编程方式绘制彩虹。

        我从 rgb(255,0,0) -> rgb(255,255,0) -> rgb(0,255,0) -> rgb(0,255,255) -> rgb(0,0,255) -> rgb( 255,0,255)。

        我使用我的RainbowVis-JS 库(它只是将渐变链接在一起)沿渐变计算十六进制颜色值。 我用 HTML5 Canvas 绘制弧形 shape,循环显示颜色。

        <!DOCTYPE html>
        <html>
          <head>
            <script src="rainbowvis.js"></script>
          </head>
          <body>
            <script type="text/javascript">
              window.onload = function(){
        
                var RAINBOW_WIDTH = 60;
                var RAINBOW_RADIUS = 130;
        
                // Library class
                var rainbow = new Rainbow();
                rainbow.setNumberRange(1, RAINBOW_WIDTH);
                rainbow.setSpectrum(
                  'FF0000', 'FFFF00', '00FF00',
                  '00FFFF', '0000FF', 'FF00FF'
                );
        
                // Canvas
                var canvas = document.getElementById('MyCanvas');
                var context = canvas.getContext('2d');
        
                context.lineWidth = 1;
                for (var i = 1; i <= RAINBOW_WIDTH; i++) {
                  context.beginPath();
                  context.arc(canvas.width/2, canvas.width/2, RAINBOW_RADIUS - i+1, 
                    Math.PI, 0, false);
                  context.strokeStyle = '#' + rainbow.colourAt(i); // Library function
                  context.stroke();
                }
              };
            </script>
            <canvas id="MyCanvas" width="300" height="300">
              <p>Rainbow arc example. Your browser doesn't support canvas.</p>
            </canvas>
          </body>
        </html>
        

        【讨论】:

          【解决方案4】:

          这个类将使用 PHP 来完成,向构造函数传递你想要的彩虹颜色数量,$sequence 属性将包含一个 rrggbb 十六进制代码数组。

          class color
          {
              public $sequence = array();
          
              /**
               * constructor fills $sequence with a list of colours as long as the $count param
               */
              public function __construct($count, $s = .5, $l = .5)
              {
                  for($h = 0; $h <= .85; $h += .85/$count)    //.85 is pretty much in the middle of the violet spectrum
                  {
                      $this->sequence[] = color::hexHSLtoRGB($h, $s, $l);
                  }
              }
          
              /**
               * from https://stackoverflow.com/questions/3597417/php-hsv-to-rgb-formula-comprehension#3642787
               */
              public static function HSLtoRGB($h, $s, $l)
              {
          
                  $r = $l;
                  $g = $l;
                  $b = $l;
                  $v = ($l <= 0.5) ? ($l * (1.0 + $s)) : (l + $s - l * $s);
                  if ($v > 0){
                        $m;
                        $sv;
                        $sextant;
                        $fract;
                        $vsf;
                        $mid1;
                        $mid2;
          
                        $m = $l + $l - $v;
                        $sv = ($v - $m ) / $v;
                        $h *= 6.0;
                        $sextant = floor($h);
                        $fract = $h - $sextant;
                        $vsf = $v * $sv * $fract;
                        $mid1 = $m + $vsf;
                        $mid2 = $v - $vsf;
          
                        switch ($sextant)
                        {
                              case 0:
                                    $r = $v;
                                    $g = $mid1;
                                    $b = $m;
                                    break;
                              case 1:
                                    $r = $mid2;
                                    $g = $v;
                                    $b = $m;
                                    break;
                              case 2:
                                    $r = $m;
                                    $g = $v;
                                    $b = $mid1;
                                    break;
                              case 3:
                                    $r = $m;
                                    $g = $mid2;
                                    $b = $v;
                                    break;
                              case 4:
                                    $r = $mid1;
                                    $g = $m;
                                    $b = $v;
                                    break;
                              case 5:
                                    $r = $v;
                                    $g = $m;
                                    $b = $mid2;
                                    break;
                        }
                  }
                  return array('r' => floor($r * 255.0),
                              'g' => floor($g * 255.0), 
                              'b' => floor($b * 255.0)
                              );
              }
          
              //return a hex code from hsv values
              public static function hexHSLtoRGB($h, $s, $l)
              {
                  $rgb = self::HSLtoRGB($h, $s, $l);
                  $hex = base_convert($rgb['r'], 10, 16) . base_convert($rgb['g'], 10, 16) . base_convert($rgb['b'], 10, 16);
                  return $hex;
              }
          }
          

          测试例如:

          $c = new color(100);
          foreach($c->sequence as $col)
            print "<div style='background-color:#$col'>$col</div>\n";
          

          我只声称将其打包成一个类,原始功能在这篇文章中找到: PHP HSV to RGB formula comprehension

          【讨论】:

            【解决方案5】:

            最简单的方法是在此序列中的每个连续对之间进行线性插值(以 RGB 为单位):

            • #ff0000
            • #ffff00黄色
            • #00ff00绿色
            • #00ffff青色
            • #0000ff蓝色
            • #ff00ff洋红色
            • #ff0000回红

            这应该得到与扫描 HSV 或 HSL 中的色调值几乎相同的结果,但可以让您直接在 RGB 中工作。请注意,每次插值仅更改一个组件,这简化了事情。这是一个 Python 实现:

            def rainbow():
              r, g, b = 255, 0, 0
              for g in range(256):
                yield r, g, b
              for r in range(255, -1, -1):
                yield r, g, b
              for b in range(256):
                yield r, g, b
              for g in range(255, -1, -1):
                yield r, g, b
              for r in range(256):
                yield r, g, b
              for b in range(255, -1, -1):
                yield r, g, b
            

            【讨论】:

            • 一个小问题是彩虹以紫色结束,而不是红色。
            • 是的。 HSL 和 HSV 解决方案也存在此问题。
            【解决方案6】:
            • 红色(网页颜色)(十六进制:#FF0000)(RGB:255, 0, 0)
            • 橙色(色轮橙色)(十六进制:#FF7F00)(RGB:255、127、0)
            • 黄色(网页颜色)(十六进制:#FFFF00)(RGB:255、255、0)
            • 绿色 (X11)(电绿色)(HTML/CSS “石灰”)(色轮绿色)(十六进制:#00FF00)(RGB:0、255、0)
            • 蓝色(网页颜色)(十六进制:#0000FF)(RGB:0、0、255)
            • 靛蓝(电靛蓝)(十六进制:#6600FF)(RGB:102、0、255)
            • 紫罗兰色(电紫罗兰色)(十六进制:#8B00FF)(RGB:139、0、255)

            在每种颜色之间进行线性插值。

            【讨论】:

            • 线性插值在哪个颜色空间中? ;)
            • 当然是 RGB。您可能会将这一点用于线性插值 #FF0000 #FFFF00 #00FF00 #00FFFF #0000FF #FF00FF #FF0000 在这种情况下它看起来不太自然。在制作精美的玻璃 RGB 照明时,我采用了“彩虹”颜色插值
            • 以鲜艳的紫罗兰而不是电紫罗兰结束不是更好吗?
            • 我在看en.wikipedia.org/wiki/Violet_(color),上面写着电紫在紫光谱的中间,而鲜艳的紫在最边缘。
            【解决方案7】:

            您可以使用HSV color space 并穿过色调维度。

            【讨论】:

              【解决方案8】:

              改用 HSL:固定亮度和饱和度并将色调从 0 更改为 360,然后转换为 RGB。

              HSL 描述人们感知的颜色。 RGB 将它们描述为机​​器使用它们。所以你不能直接使用 RGB 做任何视觉上令人愉悦的事情。

              【讨论】:

                猜你喜欢
                • 2011-03-12
                • 1970-01-01
                • 2021-12-28
                • 1970-01-01
                • 1970-01-01
                • 2018-01-26
                • 1970-01-01
                • 2012-07-10
                • 1970-01-01
                相关资源
                最近更新 更多