熱画像だと、温かいところが赤、冷たいところが青、中間が緑、というのがよくあるが、これは輝度と値が比例しないので、慣れないと理解しづらいという問題がある。また、印刷する際にカラーで印刷しないと情報が失われてしまうので、紙ベースで処理してコストを気にするようなところでは、モノクロで印刷しても情報が失われない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 件のコメント:
コメントを投稿