连续迭代 RGB?
iterating over RGB continuously?
我正在尝试迭代 RGB 值,以获得连续的色板。
通常,要遍历 3 个值并获取所有值,您可以像在二进制中那样做:
r g b
0 0 0
0 0 1
0 1 0
但我有一个主要问题。我们需要让他们的订单看起来连续,例如,我查看 红色,而不是橙色,而不是黄色、绿色等。
我应该使用什么算法或伪代码来获得它们的顺序??
查看所附图片,颜色应该是这样的:
从 HSB 或 HSL 值开始,然后将它们转换为 RGB。
当您选择亮度 (B) 和饱和度 (S) 时,您可以通过不断改变色调 (H) 的值来获得您想要的效果
如果你google你会找到进行转换的公式
从255 0 0开始,然后g向上数到255 255 0,然后红色向下数到0 255 0,然后蓝色向上数到0 255 255,然后绿色向下数到0 0 255,然后向上数红色到 255 0 255,然后蓝色倒数到 255 0 0.
您需要的是颜色的线性插值,以实现从一种颜色到另一种颜色的平滑过渡。我会给你一个简单的练习,让你理解所涉及的数学。
Red = (1, 0, 0)
Yellow = (1, 1, 0) (lies exactly between red and yellow)
Green = (0, 1, 0)
首先从红色插值到黄色。由于 x
和 z
保持不变,因此唯一要插入的分量是 y
。平滑度取决于您从一个极端到另一个极端停了多少次。假设我们采取止损 = 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) |
+------------+------------+
如果您从 Red -> Yellow -> Green -> Cyan -> Blue -> Magenta
进行插值,您会得到一条线,其中一个极端是红色,另一个是洋红色。
现在要创建您在问题中发布的 HSV wheel,需要进行径向和轴向插值。
Hue(或实际颜色)是径向插值的,即基于角度。这里的平滑度(停止)将基于角度而不是距离。
+-------+-------+
|Angle° |Colour |
+-------+-------+
|0/360 |Red |
+-------+-------+
|60 |Yellow |
+-------+-------+
|120 |Green |
+-------+-------+
|180 |Cyan |
+-------+-------+
|240 |Blue |
+-------+-------+
|300 |Magenta|
+-------+-------+
饱和度(鲜艳度)是径向插值的,即基于点与中心的距离。中心为纯白色,圆周为纯色
因此,从中心到圆周的直线以 0° 的角度从中心开始为白色 (1, 1, 1),在圆周处以纯红色 (1, 0, 0) 结束。对其他角度也做同样的事情(直到你回到 360/0°),你就会得到你发布的轮子;它实际上是一个来自更大 (HSV) 圆柱体的圆盘,其垂直轴将插入 Lightness(上面链接的维基百科优秀文章中的图片)。
有关 HSV 轮的实时渲染,请参阅下面的代码。
// REFERENCES
//
//
// 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>
我正在尝试迭代 RGB 值,以获得连续的色板。 通常,要遍历 3 个值并获取所有值,您可以像在二进制中那样做:
r g b
0 0 0
0 0 1
0 1 0
但我有一个主要问题。我们需要让他们的订单看起来连续,例如,我查看 红色,而不是橙色,而不是黄色、绿色等。
我应该使用什么算法或伪代码来获得它们的顺序??
查看所附图片,颜色应该是这样的:
从 HSB 或 HSL 值开始,然后将它们转换为 RGB。
当您选择亮度 (B) 和饱和度 (S) 时,您可以通过不断改变色调 (H) 的值来获得您想要的效果
如果你google你会找到进行转换的公式
从255 0 0开始,然后g向上数到255 255 0,然后红色向下数到0 255 0,然后蓝色向上数到0 255 255,然后绿色向下数到0 0 255,然后向上数红色到 255 0 255,然后蓝色倒数到 255 0 0.
您需要的是颜色的线性插值,以实现从一种颜色到另一种颜色的平滑过渡。我会给你一个简单的练习,让你理解所涉及的数学。
Red = (1, 0, 0)
Yellow = (1, 1, 0) (lies exactly between red and yellow)
Green = (0, 1, 0)
首先从红色插值到黄色。由于 x
和 z
保持不变,因此唯一要插入的分量是 y
。平滑度取决于您从一个极端到另一个极端停了多少次。假设我们采取止损 = 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) | +------------+------------+
如果您从 Red -> Yellow -> Green -> Cyan -> Blue -> Magenta
进行插值,您会得到一条线,其中一个极端是红色,另一个是洋红色。
现在要创建您在问题中发布的 HSV wheel,需要进行径向和轴向插值。
Hue(或实际颜色)是径向插值的,即基于角度。这里的平滑度(停止)将基于角度而不是距离。
+-------+-------+ |Angle° |Colour | +-------+-------+ |0/360 |Red | +-------+-------+ |60 |Yellow | +-------+-------+ |120 |Green | +-------+-------+ |180 |Cyan | +-------+-------+ |240 |Blue | +-------+-------+ |300 |Magenta| +-------+-------+
饱和度(鲜艳度)是径向插值的,即基于点与中心的距离。中心为纯白色,圆周为纯色
因此,从中心到圆周的直线以 0° 的角度从中心开始为白色 (1, 1, 1),在圆周处以纯红色 (1, 0, 0) 结束。对其他角度也做同样的事情(直到你回到 360/0°),你就会得到你发布的轮子;它实际上是一个来自更大 (HSV) 圆柱体的圆盘,其垂直轴将插入 Lightness(上面链接的维基百科优秀文章中的图片)。
有关 HSV 轮的实时渲染,请参阅下面的代码。
// REFERENCES
//
//
// 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>