熱画像だと、温かいところが赤、冷たいところが青、中間が緑、というのがよくあるが、これは輝度と値が比例しないので、慣れないと理解しづらいという問題がある。また、印刷する際にカラーで印刷しないと情報が失われてしまうので、紙ベースで処理してコストを気にするようなところでは、モノクロで印刷しても情報が失われないIron paletteのほうが良い。輝度と値が比例するので、慣れていなくてもぱっと見て理解できる、という利点もある。
javascript - Thermal imaging palette - Stack Overflow
適当な大きさのパレットで持って、中間は補完しろ、みたいなことが書いてある。
***
色をグラフ化すると、なんとなく波形っぽいので、とりあえず正弦波で近似してみた。
1色あたり、8個のパラメータが必要になる。C#で乱数を作って、FLIRの画像から取り出したスケールとの差を最小になるパラメータを書き出した。500万セットくらい乱数を作っているが、5分位で処理できる。アルゴリズム上の問題で500万セットくらいしか処理できないが、アルゴリズムを修正すれば寝てる間に500倍くらいの乱数セットを処理できそう。
ただ、今は1色ごとをFLIRの値と比較しているが、本来であれば輝度へ変換した上で、輝度のリニアリティを優先するべき。このあたりは追々。
値から色に変換するには、値を0-1で正規化して、(sin(値*周期1+位相1)*ゲイン1+オフセット1)*(sin(値*周期2+位相2)*ゲイン2*オフセット2)で計算できる。
上記のパラメータではこんな感じ。
かなり綺麗に表現できてる気がする。
三角関数が6個必要なので、組み込みだと計算負荷が高め。ま、組み込みでこういうスケールが必要な事態は少ないだろうし、問題ないはず。PCとかで処理するなら、三角関数で好きなだけ分解能を増やせる。
緑の片方はゲインが0に近いので、正弦波5個で計算できるかも。
最初はパラメータを手動で設定していたけど、乱数で設定したら簡単にそれっぽい値にできた。それなりに時間はかかるけど、放置しておけば終わるので楽。
もうちょっと色々試してみる予定。
追記:2017/12/25
アルゴリズムを変えて生成してみた。
微妙に直線性が悪い気がするのと、グレーがなんとなくガタガタしてる気がする。
とりあえず0で輝度が10%、1で輝度が85%になるような値になっている。0が完全な黒ではなく、1も完全な白ではない。背景が真っ黒のページにグラフを表示しても境界がわかりやすいし、真っ白な紙に印刷しても同様。
なんとなく1側が青白くて、輝度が低い気がする。
とりあえず以下のソースコードは別言語への移植も含めて自由に使っていいです。完全無保証無サポートですけど。あとFLIR Systemsとかに怒られても知らないけど(あ、怒られたら怒られたって教えてくれると助かります)。
C# src
public class Iron_palette
{
protected const double R_f1 = 0.5107;
protected const double R_f2 = 0.6085;
protected const double G_f1 = 2.9332;
protected const double G_f2 = 0.0599;
protected const double B_f1 = 4.6611;
protected const double B_f2 = 0.646;
protected const double R_p1 = 1.0094;
protected const double R_p2 = 2.8977;
protected const double G_p1 = 1.193;
protected const double G_p2 = 0.8202;
protected const double B_p1 = 1.5839;
protected const double B_p2 = 1.0357;
protected const double R_g1 = 3.8616;
protected const double R_g2 = 2.3461;
protected const double G_g1 = 4.2843;
protected const double G_g2 = 0.2103;
protected const double B_g1 = 2.7105;
protected const double B_g2 = 1.6943;
protected const double R_o1 = -3.2597;
protected const double R_o2 = 2.1916;
protected const double G_o1 = -4.9513;
protected const double G_o2 = -0.2657;
protected const double B_o1 = 2.8918;
protected const double B_o2 = -1.4018;
public static Color to_color(double value)
{
if (value < 0 || value > 1)
{
throw (new ArgumentOutOfRangeException());
}
return (Color.FromArgb(
(int)(
(Math.Sin(value * R_f1 + R_p1) * R_g1 + R_o1) *
(Math.Sin(value * R_f2 + R_p2) * R_g2 + R_o2) *
255),
(int)(
(Math.Sin(value * G_f1 + G_p1) * G_g1 + G_o1) *
(Math.Sin(value * G_f2 + G_p2) * G_g2 + G_o2) *
255),
(int)(
(Math.Sin(value * B_f1 + B_p1) * B_g1 + B_o1) *
(Math.Sin(value * B_f2 + B_p2) * B_g2 + B_o2) *
255)));
}
}
それぞれの三角関数の値。左上の、ガタガタしてるのはFLIRの画像から拾ってきた輝度。
ざっと眺める感じ、1個の直線+1個の三角関数、で近似できそうな気がしてきた。Rs2はほとんど直線っぽいし、Gs2もほとんど直線。Bs2は微妙に曲線だけど、これくらいなら直線で近似できるんじゃないかなぁ。
あとで片方直線、片方三角関数、でパラメータを探ってみよう。
何かのシミュレーション結果をIron palettesで動画化する場合、4k動画なら1枚で約50M回のsin計算が必要になる。60fpsで1分の動画なら180G回のsin計算が必要になる。これが半分になれば結構大きい気がする。




0 件のコメント:
コメントを投稿