4

I am trying to iterate over RGB values, to get a continuously colour plate . Usually ,to iterate over 3 values and get them all, you do it like in binary:

r g b 
0 0 0 
0 0 1
0 1 0

But i have one main issue. We need to get their order to looks continuously so for instance, i go over the reds, than right to the orange, than to the yellow,green, etc.

What algorithm ,or pseudo code should i use to get them in that order ??

See this image attached, how the colors should look like: enter image description here

Curnelious
  • 1
  • 16
  • 76
  • 150

4 Answers4

8

Start from 255 0 0, then count up g to 255 255 0, then count down red to 0 255 0, then count up blue to 0 255 255, then count down green to 0 0 255, then count up red to 255 0 255, then count down blue to 255 0 0.

Christopher Moore
  • 15,626
  • 10
  • 42
  • 52
acenturyandabit
  • 1,188
  • 10
  • 24
3

Start from HSB or HSL values then convert them to RGB.

As you choose Brightness (B) and Saturation (S) you get what you want by changing continuously the value for Hue (H)

If you google you'll find formulas to do the conversion

Paolo
  • 15,233
  • 27
  • 70
  • 91
0

What you need is linear interpolation of colours to give that smooth transition from one color to another. I'll give a simple workout for you to understand the math involved.

Red = (1, 0, 0)

Yellow = (1, 1, 0) (lies exactly between red and yellow)

Green = (0, 1, 0)

First interpolate from red to yellow. Since x and z stay the same, the only component to interpolate is y. The smoothness depends on how many stops you make from one extreme to the other. Say we take stops = 4

+------------+------------+
|Red         |(1, 0, 0)   |
+------------+------------+
|            |(1, 0.2, 0) |
+            +------------+
|            |(1, 0.4, 0) |
+  Yellowish +------------+
|     Red    |(1, 0.6, 0) |
+            +------------+
|            |(1, 0.8, 0) |
+------------+------------+
|Yellow      |(1, 1, 0)   |
+------------+------------+
|            |(0.8, 1, 0) |
+            +------------+
|            |(0.6, 1, 0) |
+ Yellowish  +------------+
|   Green    |(0.4, 1, 0) |
+            +------------+
|            |(0.2, 1, 0) |
+------------+------------+
|Green       |(0, 1, 0)   |
+------------+------------+

If you interpolate from Red -> Yellow -> Green -> Cyan -> Blue -> Magenta you'd get a line with one extreme being Red and the other being Magenta.

Now to create the HSV wheel you've posted in your question, one needs to do both radial and axial interpolaton.

Hue (or the actual colour) is radially interpolated i.e. based on the angle. The smoothness (stops) here would be based on angle instead of distance.

+-------+-------+
|Angle° |Colour |
+-------+-------+
|0/360  |Red    |
+-------+-------+
|60     |Yellow |
+-------+-------+
|120    |Green  |
+-------+-------+
|180    |Cyan   |
+-------+-------+
|240    |Blue   |
+-------+-------+
|300    |Magenta|
+-------+-------+

Saturation (vividness) is interpolated radially i.e. based on the point's distance from the centre. The centre is pure white while the point at the circumference is pure colour.

So the line from centre to circumference at angle 0° would start with white (1, 1, 1) at centre and end with pure red (1, 0, 0) at circumference. Do the same for the other angles too (until you circle back to 360/0°) and you'd get the wheel you've posted; it's actually a disc from a greater (HSV) cylinder whose vertical axis would interpolate Lightness (picture in Wikipedia's excellent article linked above).

See code below for a live rendering of a HSV wheel.

         // REFERENCES
         // http://stackoverflow.com/q/10373695
         // http://stackoverflow.com/a/7541756
         // http://tutorials.jenkov.com/html5-canvas/gradients.html
         // Computer Graphics: From Pixels to Programmable Graphics
         // Hardware by Alexey Boreskov, Evgeniy Shikin

         // from rgb_hsv_lerp workout
         function hsv2rgb(h) {
             var s = 1, v = 1;
             while(h < 0) h += 360;
             while(h >= 360) h -= 360;
             h /= 60;
             var i = Math.floor(h);
             var f = h - i;
             var p = v * (1 - s);
             var q = v * (1 - (s * f));
             var t = v * (1 - (s * (1 - f)));
             rgb = [];
             switch(i) {
                 case 0: rgb[0] = v; rgb[1] = t; rgb[2] = p; break;
                 case 1: rgb[0] = q; rgb[1] = v; rgb[2] = p; break;
                 case 2: rgb[0] = p; rgb[1] = v; rgb[2] = t; break;
                 case 3: rgb[0] = p; rgb[1] = q; rgb[2] = v; break;
                 case 4: rgb[0] = t; rgb[1] = p; rgb[2] = v; break;
                 case 5: rgb[0] = v; rgb[1] = p; rgb[2] = q; break;
             }
             return "rgb(" + Math.floor(255 * rgb[0]) + ","
                           + Math.floor(255 * rgb[1]) + ","
                           + Math.floor(255 * rgb[2]) + ")";
         }

         function plot(ctx, x, y, hue) {
             var cx = 0, cy = 0;
             var xs = [x, -y, -x,  y];
             var ys = [y,  x, -y, -x];

             for (var i = 0; i < 4; ++i) {
                 // linear gradient from start to end of line
                 var grad = ctx.createLinearGradient(0, 0, xs[i], ys[i]);
                 grad.addColorStop(0, "white");
                 // the canvas coordinate system has Y ↓ while math coordinate
                 // has Y ↑, so flip hue too to match standard HSV wheel
                 grad.addColorStop(1, hsv2rgb(-(hue + (90 * i))));
                 ctx.strokeStyle = grad;
                 ctx.beginPath();
                 ctx.moveTo(cx, cy);
                 ctx.lineTo(xs[i], ys[i]);
                 ctx.stroke();
             }
         }

         function draw() {
             var can = document.getElementById('canvas1');
             var ctx = can.getContext('2d');
             var r = can.clientWidth / 2;

             ctx.translate(r, r);
             ctx.lineWidth = 2;

             var x = r, y = 0;
             plot(ctx, x, y, 0);
             // divide 45° by number of iterations to get iteration delta
             // y starts at 0, iteration ends when y = x i.e. x = y = r / √2
             var hue_delta = 45 / Math.floor(r / Math.sqrt(2));
             // Bresenham's circle drawing algorithm, reference book cited above
             var d = 1.25 - r;
             while (x > y) {
               ++y;
                 if (d < 0)
                     d += (2 * y) + 3;
                 else {
                     d += 2 * (y - x) + 5;
                     --x;
                 }
                 var hue = y * hue_delta;
                 plot(ctx, x, y, hue);
                 plot(ctx, y, x, 90 - hue);
             }
             ctx.translate(-r, -r);
         }
    <body onload="draw()">
        <h1>HSV Colour Wheel</h1>
        <canvas id="canvas1" width="300" height="300" />
    </body>
Community
  • 1
  • 1
legends2k
  • 31,634
  • 25
  • 118
  • 222
0

Using HSV instead of RGB makes iterating over the color wheel as simple as looping from 0 to 360 with the H value (Hue).

HSV is an alternative color represenation to RGB, which stands for "Hue, Saturation, Value (or Lightless / Brightness in HSL / HSB). Most color operations are a lot simpler to perform with HSB because all the colors are ordered in Hue (H) on a color spectrum.

Hue units are degrees on the color wheel, as shown in the reference image. Hue starts at 0 and goes until 360, both of which are red. After red, Hue 60 is Yellow. The color wheel ends after Hue 300, Magenta.

MXMLLN
  • 1,387
  • 2
  • 12
  • 12