18

我试图在 HSV 颜色空间中的两种颜色之间进行插值以产生平滑的颜色渐变。

我正在使用线性插值,例如:

h = (1 - p) * h1 + p * h2
s = (1 - p) * s1 + p * s2
v = (1 - p) * v1 + p * v2

(其中 p 是百分比,h1, h2, s1, s2, v1, v2 是两种颜色的色调、饱和度和值分量)

这对 s 和 v 产生了很好的结果,但对 h 却没有。由于色调分量是一个角度,因此计算需要计算出 h1 和 h2 之间的最短距离,然后在正确的方向(顺时针或逆时针)进行插值。

我应该使用什么公式或算法?


编辑:按照杰克的建议,我修改了我的 JavaScript 渐变函数,它运行良好。对于任何有兴趣的人,这就是我最终得到的结果:

// create gradient from yellow to red to black with 100 steps
var gradient = hsbGradient(100, [{h:0.14, s:0.5, b:1}, {h:0, s:1, b:1}, {h:0, s:1, b:0}]); 

function hsbGradient(steps, colours) {
  var parts = colours.length - 1;
  var gradient = new Array(steps);
  var gradientIndex = 0;
  var partSteps = Math.floor(steps / parts);
  var remainder = steps - (partSteps * parts);
  for (var col = 0; col < parts; col++) {
    // get colours
    var c1 = colours[col], 
        c2 = colours[col + 1];
    // determine clockwise and counter-clockwise distance between hues
    var distCCW = (c1.h >= c2.h) ? c1.h - c2.h : 1 + c1.h - c2.h;
        distCW = (c1.h >= c2.h) ? 1 + c2.h - c1.h : c2.h - c1.h;
     // ensure we get the right number of steps by adding remainder to final part
    if (col == parts - 1) partSteps += remainder; 
    // make gradient for this part
    for (var step = 0; step < partSteps; step ++) {
      var p = step / partSteps;
      // interpolate h, s, b
      var h = (distCW <= distCCW) ? c1.h + (distCW * p) : c1.h - (distCCW * p);
      if (h < 0) h = 1 + h;
      if (h > 1) h = h - 1;
      var s = (1 - p) * c1.s + p * c2.s;
      var b = (1 - p) * c1.b + p * c2.b;
      // add to gradient array
      gradient[gradientIndex] = {h:h, s:s, b:b};
      gradientIndex ++;
    }
  }
  return gradient;
}
4

2 回答 2

11

您应该只需要找出从起始色调到结束色调的最短路径。这可以很容易地完成,因为色调值的范围是 0 到 255。

您可以首先从较高的色调中减去较低的色调,然后将 256 添加到较低的色调以再次检查交换操作数的差异。

int maxCCW = higherHue - lowerHue;
int maxCW = (lowerHue+256) - higherHue;

因此,您将获得两个值,较大的值决定您应该顺时针还是逆时针。然后你必须找到一种方法来使插值在色调的模 256 上运行,所以如果你从246to插值,20如果系数是>= 0.5f你应该将色调重置为 0(因为它达到 256 并且hue = hue%256在任何情况下)。

实际上,如果您在对 0 进行插值时不关心色调,而只是在计算新色调后应用模运算符,它无论如何都应该工作。

于 2010-04-07T16:13:02.220 回答
8
于 2015-10-26T13:55:00.153 回答