Переход от более естественного спектра радуги в HSV / HSB - PullRequest
2 голосов
/ 02 марта 2011

Я пытаюсь управлять некоторыми RGB-светодиодами и переходить с красного на фиолетовый.Я использую преобразование HSV в RGB, так что я могу просто перейти от оттенка 0 к оттенку 300 (после этого он возвращается к красному).Однако проблема, которую я заметил, заключается в том, что кажется, что она проводит очень много времени в голубой и синей частях спектра.Поэтому я посмотрел, как должен выглядеть спектр ВПГ, и обнаружил, что L

enter image description here

Я не осознавал, что более половины спектра было потрачено между зеленым и синим.

Но мне бы очень хотелось, чтобы это выглядело гораздо больше так:

enter image description here

С приятной ровной смесью этих "стандартных" цветов радуги.Я предположил бы, что это в конечном итоге станет своего рода s-кривой нормальных значений оттенка, но я не совсем уверен, как рассчитать эту кривую.

Реальный алгоритм HSV to RGB, который обрабатывает это внутренне, будетбыть отличным (любой код на самом деле, хотя он и для Arduino), но даже просто объяснение того, как я могу рассчитать эту кривую оттенка, будет высоко оценено.

Ответы [ 2 ]

2 голосов
/ 02 марта 2011

http://www.fourmilab.ch/documents/specrend/ содержит довольно подробное описание того, как преобразовать длину волны в компоненты CIE (которые примерно соответствуют выходным сигналам трех типов конических датчиков в ваших глазах), а затем как преобразовать их в значения RGB (с предупреждением, что некоторые длины волн не имеют эквивалентов RGB в типичной гамме RGB).

Или: существуют различные «воспринимаемые однородные цветовые пространства», такие как CIE L * a * b * (см., Например, http://en.wikipedia.org/wiki/Lab_color_space);, вы можете выбрать один из них, сделать равные шаги вдоль прямой линии, соединяющей ваш старт и конец цвета в этом пространстве и конвертировать в RGB.

Любой из них, вероятно, будет излишним для вашего приложения, и нет никаких очевидных причин, почему они должны быть намного - или любой - лучше, чем что-то более простое и чисто эмпирическое. Так почему бы не сделать следующее:

  1. Выберите начальный и конечный цвета. Для простоты предположим, что они имеют S = 1 и V = 1 в пространстве HSV. Запишите их вниз.
  2. Посмотрите на оттенок "спектр", который вы разместили, и найдите цвет, который выглядит вам примерно посередине между вашей начальной и конечной точками. Запишите это.
  3. Теперь снова пополам: найдите цвета на полпути между началом и серединой и на полпути между серединой и концом.
  4. Повторите один или два раза больше, чтобы вы разбили шкалу оттенков на 8 или 16 "перцептивно равных" частей.
  5. Преобразовать в RGB, вставить их в таблицу поиска и выполнить линейную интерполяцию между ними.
  6. Изменяйте значения RGB, пока у вас не получится что-то, что выглядит хорошо.

Это совершенно нереально, и в нем нет ничего принципиального, но, вероятно, он будет работать довольно хорошо, и окончательный код будет в основном тривиальным:

void compute_rgb(int * rp, int * gp, int * bp, int t) {
  // t in the range 0..255 (for convenience)
  int segment = t>>5; // 0..7
  int delta = t&31;
  int a=rgb_table[segment].r, b=rgb_table[segment+1].r;
  *rp = a + ((delta*(b-a))>>5);
  a=rgb_table[segment].g; b=rgb_table[segment+1].g;
  *gp = a + ((delta*(b-a))>>5);
  a=rgb_table[segment].b; b=rgb_table[segment+1].b;
  *bp = a + ((delta*(b-a))>>5);
}

(вы можете сделать код несколько понятнее, если не хотите сохранять каждый доступный цикл).

Что бы это ни стоило, мои глаза ставят точки деления на значения оттенков около (0), 40, 60, 90, 150, 180, 240, 270, (300). Ваш пробег может отличаться.

1 голос
/ 30 июля 2018

FastLED делает версию этого: https://github.com/FastLED/FastLED/wiki/FastLED-HSV-Colors

Fast LED HSV

HSLUV является еще одним вариантом: http://www.hsluv.org/. У них есть библиотеки вкуча разных языков.

HSLUV

Также, это интересная техника: https://www.shadertoy.com/view/4l2cDm

const float tau = acos(-1.)*2.;

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;

    vec3 rainbow = sqrt( //gamma
        sin( (uv.x+vec3(0,2,1)/3.)*tau ) * .5 + .5
    );

    fragColor.rgb = rainbow;
}

enter image description here

Также см .: https://en.wikipedia.org/wiki/Rainbow#Number_of_colours_in_spectrum_or_rainbow для получения дополнительной информации.

...