🚨

HSL色表現をフルカラーLEDに反映する方法

2022/12/28に公開


色相を一周している

やりたいこと

RGB 形式は直感的でないため HSL を使って最後に RGB に変換して反映したい。

https://ja.wikipedia.org/wiki/HLS色空間

を見ると変換アルゴリズムが書いてあるがこの類のものはだいたい先駆者がライブラリを用意してくれている。そこで HSL をキーワードにして探してみると ColorConverter というのがあったのでこれを使わせてもらう。

ところがライブラリが動かない

https://github.com/luisllamasbinaburo/Arduino-ColorConverter

README には Deprecated と書かれてあるし、ソースを見みても RGBConverter.h を読み込もうとしているのに実際のヘッダーファイルは ColorConverter.h だったりと整合性が取れていない。そこで自力で修正を試みるもコンパイルできなかった。仕方がないので必要な箇所だけ抜粋して使わせてもらうことにする。

hsl_to_rgb.ino
void hsl_to_rgb(double h, double s, double l, uint8_t& red, uint8_t& green, uint8_t& blue) {
  double r, g, b;
  if (s == 0) {
    r = g = b = l; // achromatic
  } else {
    auto q = l < 0.5 ? l * (1 + s) : l + s - l * s;
    auto p = 2 * l - q;
    r = hue_to_rgb(p, q, h + 1 / 3.0);
    g = hue_to_rgb(p, q, h);
    b = hue_to_rgb(p, q, h - 1 / 3.0);
  }
  red   = static_cast<uint8_t>(r * 255);
  green = static_cast<uint8_t>(g * 255);
  blue  = static_cast<uint8_t>(b * 255);
}

double hue_to_rgb(double p, double q, double t) {
  if (t < 0) t += 1;
  if (t > 1) t -= 1;
  if (t < 1 / 6.0) return p + (q - p) * 6 * t;
  if (t < 1 / 2.0) return q;
  if (t < 2 / 3.0) return p + (q - p) * (2 / 3.0 - t) * 6;
  return p;
}

コード

上の hsl_to_rgb.ino は、この sketch_main.ino と同じ場所に置いておく。

sketch_main.ino
void setup() {
}

uint64_t count = 0;

void loop() {
  double h = fmod(1.0 / (60 * 4) * count, 1.0); // 1周4秒
  double s = 1.0;
  double l = 0.1;

  uint8_t r, g, b;
  hsl_to_rgb(h, s, l, r, g, b);

  analogWrite(6, r);
  analogWrite(5, g);
  analogWrite(3, b);

  count++;
  delay(1000 / 60);
}
  • 色相(H)
    • 一周 1.0
  • 彩度(S)
    • 0.5 なら色味が薄く淡い感じになる
    • 1.0 でいちばん色味が強くでる
  • 輝度(L)
    • 0.1 ぐらいでじゅうぶん明るい (CSS なら 0.1 はかなり暗いはずだけど)
    • 0.5 だと明るすぎて白に近い
  • 疑問
    • 輝度固定にしても色によって明るさが異なってるように感じる

Discussion