Как интерполировать значения оттенка в цветовом пространстве HSV?

Я пытаюсь интерполировать между два, раскрашивает цветовое пространство 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 и затем сделать интерполяцию в правильном направлении (или по часовой стрелке или против часовой стрелки).

Какую формулу или алгоритм я должен использовать?


Править: Предложениями следующего Jack's я изменил свою функцию градиента 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;
}
15
задан nick 8 April 2010 в 11:00
поделиться

1 ответ

Вам просто нужно найти кратчайший путь от начального оттенка до конечного оттенка. Это легко сделать, поскольку значения оттенка находятся в диапазоне от 0 до 255.

Вы можете сначала вычесть более низкий оттенок из более высокого, затем прибавить 256 к более низкому, чтобы еще раз проверить разницу с переставленными операндами.

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

Таким образом, вы получите два значения, большее из которых решает, следует ли вам двигаться по часовой стрелке или против часовой стрелки. Затем вам нужно будет найти способ заставить интерполяцию работать по модулю 256 оттенка, поэтому, если вы интерполируете от 246 до 20 , если коэффициент равен > = 0.5f , вам следует сбросить оттенок на 0 (поскольку он достигает 256 и hue = hue% 256 в любом случае).

На самом деле, если вы не заботитесь об оттенке при интерполяции по 0, а просто применяете оператор по модулю после вычисления нового оттенка, он все равно должен работать.

11
ответ дан 1 December 2019 в 04:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: