Интерполяция цвета
- Войдите на сайт для отправки комментариев
Сб, 19/12/2020 - 18:52
Здравствуйте, делаю подсветку на адресной ленте - плавное переливание светодиодов. Использую библиотеку FastLed
#define NUM_LEDS 1
#include "FastLED.h"
#include "lib8tion.h"
#define PIN 3
CRGB leds[NUM_LEDS];
CHSV targetColor[NUM_LEDS];
void setup()
{
for (uint16_t i = 0; i < NUM_LEDS; i++)
{
targetColor[i] = CHSV(random(0, 255), random(0, 255), random(0, 255));
}
Serial.begin(9600);
randomSeed(2648469515618); // read noise from component for set rnd seed
FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness(255);
pinMode(PIN, OUTPUT);
}
CHSV RgbToHsv(CRGB rgb)
{
CHSV hsv;
unsigned char rgbMin, rgbMax;
rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
hsv.v = rgbMax;
if (hsv.v == 0)
{
hsv.h = 0;
hsv.s = 0;
return hsv;
}
hsv.s = 255 * long(rgbMax - rgbMin) / hsv.v;
if (hsv.s == 0)
{
hsv.h = 0;
return hsv;
}
if (rgbMax == rgb.r)
hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
else if (rgbMax == rgb.g)
hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
else
hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);
return hsv;
}
CHSV InterpolateColor(CHSV a, CHSV b)
{
float ah = a.h;
float as = a.s;
float av = a.v;
float bh = b.h;
float bs = b.s;
float bv = b.v;
ah = ah + (bh - ah) * 0.3;
as = as + (bs - as) * 0.3;
av = av + (bv - av) * 0.3;
return CHSV(ah, as, av);
}
void loop()
{
for (uint16_t i = 0; i < NUM_LEDS; i++)
{
CHSV col = RgbToHsv(leds[i]);
col = InterpolateColor(col, targetColor[i]);
Serial.print(col.h);
Serial.print(" ");
Serial.print(col.s);
Serial.print(" ");
Serial.println(col.v);
Serial.print(targetColor[i].h);
Serial.print(" ");
Serial.print(targetColor[i].s);
Serial.print(" ");
Serial.println(targetColor[i].v);
if (
abs(col.h - targetColor[i].h) < 4 &&
abs(col.s - targetColor[i].s) < 4 &&
abs(col.v - targetColor[i].v) < 4)
{
targetColor[i] = CHSV(random(0, 255), random(0, 255), random(0, 255));
}
leds[i] = col;
}
delay(10);
FastLED.show();
}
В один момент цвета перестают меняться.

Проверил ту же формулу на числе uint8_t все работает. В чем проблема?
Какую формулу?
Функция считает по формуле a+(b-a) * t где 0<= t <=1
Так а что не работает?
В один момент цвета перестают меняться.
Проверил ту же формулу на числе uint8_t все работает. В чем проблема?
Есть цвет пикселя - случайный. Есть цвет пикселя который нам нужен - тоже случайный. Оно должно плавно переливаться из цвета который уже имеется в тот, который нам нужен. Цвет несколько раз меняется, а потом перестает, не дойдя до нужного значения. Не понимаю почему
В fastled уже есть всё необходимое. Не надо ничего самому изобретать.
В fastled уже есть всё необходимое. Не надо ничего самому изобретать.
Я нашел функцию lerp8by8, но не понял как ей дать значение frac меньше 1. Покажите пример если не сложно
Цвет несколько раз меняется, а потом перестает, не дойдя до нужного значения. Не понимаю почему
Программа работает в точности так, как она написана.
Расставьте комментарии в тексте. Может, сами найдете проблему, а может, мы найдем, где код не совпадает с комментариями. Гадать, как должно быть, и прочему в коде написано именно так, а не иначе (не зная, как должно быть), - дело неблагодарное.
Переведите цвет в CHS и вообще ничего делать не надо
#define NUM_LEDS 1 //количество светодиодов в ленте. 1 - для простоты отладки #include "FastLED.h" #include "lib8tion.h" #define PIN 3 CRGB leds[NUM_LEDS]; // текущий цвет светодиодов CHSV targetColor[NUM_LEDS]; // требуемый цвет светодиодов void setup() { for (uint16_t i = 0; i < NUM_LEDS; i++) { targetColor[i] = CHSV(random(0, 255), random(0, 255), random(0, 255)); // случайно заполняем требуемые цвета } Serial.begin(9600); randomSeed(2648469515618); // read noise from component for set rnd seed FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );//инициализируем ленту FastLED.setBrightness(255); //ставим макс яркость pinMode(PIN, OUTPUT); } CHSV RgbToHsv(CRGB rgb)//преобразование ргб в хсв. Точно рабочий, много где использовал - проблем небыло { CHSV hsv; unsigned char rgbMin, rgbMax; rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b); rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b); hsv.v = rgbMax; if (hsv.v == 0) { hsv.h = 0; hsv.s = 0; return hsv; } hsv.s = 255 * long(rgbMax - rgbMin) / hsv.v; if (hsv.s == 0) { hsv.h = 0; return hsv; } if (rgbMax == rgb.r) hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin); else if (rgbMax == rgb.g) hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin); else hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin); return hsv; } CHSV InterpolateColor(CHSV a, CHSV b) // функция интерполяции { float ah = a.h; // берем тон цвета a. a - тот который есть float as = a.s; // берем насыщенность а float av = a.v; // берем яркость а float bh = b.h; // берем тон б. б - тот который нужен float bs = b.s; // берем насыщенность float bv = b.v; // берем яркость ah = ah + (bh - ah) * 0.3; // считаем as = as + (bs - as) * 0.3; av = av + (bv - av) * 0.3; return CHSV(ah, as, av);//возвращаем новый цвет } void loop() { for (uint16_t i = 0; i < NUM_LEDS; i++) //проходим по всем светодиодам ленты { CHSV col = RgbToHsv(leds[i]); //берем ргб цвет, переводим в хсв col = InterpolateColor(col, targetColor[i]); // интерполируем Serial.print(col.h); //отладочная информация Serial.print(" "); Serial.print(col.s); Serial.print(" "); Serial.println(col.v); Serial.print(targetColor[i].h); Serial.print(" "); Serial.print(targetColor[i].s); Serial.print(" "); Serial.println(targetColor[i].v); if ( abs(col.h - targetColor[i].h) < 4 && abs(col.s - targetColor[i].s) < 4 && abs(col.v - targetColor[i].v) < 4) // сравниваем получившийся цвет и тот который нужен с допуском 4 { targetColor[i] = CHSV(random(0, 255), random(0, 255), random(0, 255)); // если совпало - меняем нужный нам цвет } leds[i] = col; // присваиваем полученный цвет тому, который отображается } delay(10); //ждем для плавнности FastLED.show(); // показываем }Программа работает в точности так, как она написана.
Да, с простым числом все работает так, как оно и должно. Но с цветом что то не так, хотя действия те же самые.
Программа всегда работает так, как написана.
1. Как должна работать программа?
2. Как она на самом деле работает?
3. Чем 1 отличается от 2?
Я не в теме FastLed. Может поэтому для меня не очевидно, почему в строке 077 вы присваиваете через преобразование, а в строке 101 без преобразования.
Фастлед в одну сторону сам умеет конвертить цветовые пространства.
Программа всегда работает так, как написана.
1. Как должна работать программа?
2. Как она на самом деле работает?
3. Чем 1 отличается от 2?
1. должна плавно менять цвет н-ого числа светодиодов по hue до требуемого
2. плавно меняет цвет светодиода, но не доходит до требуемого
3. цвет не доходит до требуемого значения
Я не в теме FastLed. Может поэтому для меня не очевидно, почему в строке 077 вы присваиваете через преобразование, а в строке 101 без преобразования.
077: я не нашел как из rgb сделать hsv цвет в библиотеке fastled.
101: если переменной с типом CRGB присваивать переменную с типом CHSV то все работает, но не наоборот
Константин, несколько вопросов по коду
1. Если у вас вся работа с цветом в CHSV, зачем начальный цвет в RGB ?
задайте сразу весь цвет в CHSV и сложная конверсия будет не нужна. Я не вникал в детали вашей процедуры RgbToHsv() - но в ней легко может быть ошибка. А задав цвет в CHSV вы заведомо исключите этот источник проблем.
2. Теперь интерполяция цвета
CHSV InterpolateColor(CHSV a, CHSV b) // функция интерполяции { float ah = a.h; // берем тон цвета a. a - тот который есть float as = a.s; // берем насыщенность а float av = a.v; // берем яркость а float bh = b.h; // берем тон б. б - тот который нужен float bs = b.s; // берем насыщенность float bv = b.v; // берем яркость ah = ah + (bh - ah) * 0.3; // считаем as = as + (bs - as) * 0.3; av = av + (bv - av) * 0.3; return CHSV(ah, as, av);//возвращаем новый цвет }зачем компоненты цвета имеют тип float? - они же целые
И почему в вашем понимании интерполяция - это именно 0.3 от разницы компонентов цвета? - логичнее было бы 0.5
Если же вы хотите интерполяцию за несколько шагов, то нужно разделить разность величин ah и bh на число отрезков, равное числу шагов... А число 0.3 - это ни к селу ни к городу...
Константин, несколько вопросов по коду
1. Если у вас вся работа с цветом в CHSV, зачем начальный цвет в RGB ?
1. При инициализации ленты
FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );в качестве массива светодиодов принимает только массив с типом CRGB
RgbToHsv() - но в ней легко может быть ошибка
Сомневаюсь. Использую этот фрагмент где только можно - все работает.
зачем компоненты цвета имеют тип float? - они же целые
если при расчетах, как я понимаю, использовать целые числа, то оно будет округляться в ближайшую сторону. А если использовать float, то округление произойдет в конце и потерь точности будет меньше. Думал из-за этого не работает, но нет.
И почему в вашем понимании интерполяция - это именно 0.3 от разницы компонентов цвета? - логичнее было бы 0.5
так переливание выглядит плавнее.
Если же вы хотите интерполяцию за несколько шагов, то нужно разделить разность величин ah и bh на число отрезков, равное числу шагов... А число 0.3 - это ни к селу ни к городу...
Попробую если заработает
Константин, везде по исходнику, где успользуется цвет в том или ином виде, вставьте комментарии, какая цветовая модель используется.
Потому как есть подозрение, что Вы где-то в процессе вычислений путаете RGB и HSV.
И еще, Вы уверены, что (106, 16, 90) и (158, 19, 232) - это разные цвета, а не один и тот же в разных цветовых пространствах?
Надо ещё учитывать, что в HSV Fastled-а спектр на байте повторяется.
Константин, везде по исходнику, где успользуется цвет в том или ином виде, вставьте комментарии, какая цветовая модель используется.
Потому как есть подозрение, что Вы где-то в процессе вычислений путаете RGB и HSV.
И еще, Вы уверены, что (106, 16, 90) и (158, 19, 232) - это разные цвета, а не один и тот же в разных цветовых пространствах?
Проверил, все модели правильные, а при интерполяции rgb конвертируется в hsv
Да, это разные цвета.
Я бы еще распечатал значения :
- col и leds после строки 77,
- значения (разности) передаваемые в функцию abs() в строках 94-96,
- значения targetColor после строки 98,
- col и leds после строки 101.
Автор пытается Значение хранящиеся в RGB преобразовывать в HSV, интерполировть к значению хранящемуся в HSV и снова преобразовывать из HSV в RGB для сохранения. При этом преобразование RGB -> HSV -> RGB приводит к существенно другому RGB.