2013年1月16日水曜日

RGB24←HSL に必要なH,S,Lの分解能は?

  • 実験1: 任意のH,S,L分解能からRGB24へ
  • 実験2: 一様分布分解能とS-H比例分解能
  • 実験3: HSL色空間におけるRGB24全単射の分布確認


実験1: 任意のH,S,L分解能からRGB24へ


目的: RGB24→HSL(unorm)してH,S,Lそれぞれにリストを作ってソートして重複除去して隣接区間の最小差を求めたら必要分解能が決まる( ・`ω・´)

ソース: https://gist.github.com/4528935

結果:

HSL resolution from RGB24:
 H: 8.67362e-19
 S: 8.67362e-19
 L: 1.38778e-17

考察:

小さ過ぎるでござる…。この分解能で総当りすると、

1.0 / ( (8.67362e-19) * (8.67362e-19) * (1.38778e-17) )
 = 9.5781e+52

全宇宙の物質量(分子の総個数)とどっちが多いかな…たぶん宇宙かな…と言う程多い。

内部でdoubleを使おうとも所詮は有限精度の離散数学なので、RGB24→HSL変換する際に生じた小さな誤差同士の中からさらに最も小さな振れ幅を取得してこうなったんではないかと思う。

本当にこの分解能でHSLを回してRGB24を生成すると、16777216色の呈色の為に9.5781e+52色も扱う事になるから、この分解能でのHSL色空間からのRGB24色空間の変換効率は
16777216 / 9.5781e+52 = 1.75162256 × 10-46
と、言う訳で極めて悪いのでいくら何でも不採用にも程がある(;_;) …まったく関係無いけど46億年物語-遥かなるエデンへ-っていう昔のゲームを思い出した。まだたったの20年と少し前の話だよ(╹◡╹)

実験2: 一様分布分解能とS-H比例分解能

目的: HSL(unorm)→RGB24の変換をH,S,Lそれぞれに一定の分解能群を与えて生成されるRGB24色空間の充填状況を調査し妥当な分解能を探る。ついでに思い付きで一様分布分解能方式に対するS-H比例分解能方式の優位性の確認も行う。

補足: HSL色空間は色相Hと彩度Sによる円盤に明度Lを加えた円柱型の空間。HとSによる円盤面1枚に着目すると、S軸の値sに対してH軸の値hの取りうる軌道距離は2sπとなる。よってH軸の分解能r(H)が等しい場合(≈一様分布分解能)ではs値が小さい領域では空間分解能が高くなり、s値が大きい領域では空間分解能が低くなる。S-H空間分解能∝S軸分解能r(S)でこの比例定数は1であるから、H軸上の標本化密度をS軸上の値sに比例して生成すればHS面に置けるHSL色空間の分解能が一様化され標本化のエラーを低減できる(気がした)。

比例定数が1なので、あるsが先に定められる状況における理想的なH軸の分解能r(H)'は
r(H)'=(2s+1) r(H)/r(S)
とかすれば良い(のではないかと思った)。

ソース: https://gist.github.com/4531635

結果と考察: https://gist.github.com/4531768

linerが一様分布分解能方式、proportionalがS-H比例分解能方式。横軸はHSL空間の各次元の分解能、縦軸はHSL→RGB24変換した時のRGB24色空間の色数の損失数。

どうやらS-H比例分解能方式の優位性は思惑通り(╹◡╹)


H,S,Lの何れか1つの次元の分解能を半減(H|S|L>>1)させたらどうなるかの比較。liner方式ではおおよそH>L>Sの順で損失が大きくなりその順でRGB24色空間へ変換した際の呈色に重要な因子となる事が分かる。proportional方式ではL>H>Sとなった。

追加データ: https://gist.github.com/4537984

先のデータのみでは高分解能領域での挙動が大雑把過ぎるので、分解能の離散区間[512,640..1536]についてもデータを取ってみた。

( ゚д゚)…oops!高分解能領域(1400弱以上)ではproportional方式よりliner方式の方が呈色損失が少ない。proportional方式では分解能768以上では呈色損失が変化しなくなってしまっている。

うーん、これはたぶんsが極端に低い場合に生成される実際に採用されるH軸の分解能r(H)'が不足しているものと思われる。実用的には比例定数1ではなくr(H)'の生成に一定のバイアスを加えた方が良いのかも。

ちなみに: linerの近似曲線を求めると(LibreOffice-3.5 calc曰く)、

{loss} = 2.44288838093309e+029 * {resolution} ^ -8.4697648319
だそうなので変形して整理すると、

{resolution} = ( 4.09351490557271e-30 * {loss}  ) ^ -0.118067032538337
が得られる。この式で損失をどこまで抑えたいかを変数にliner方式における各成分の分解能を推論できる。この式を横軸を損失数、縦軸を各成分の分解能として図示すると、
となる。損失を区間[0-10000]に絞って拡大して見ると、
1万色損失しても構わない場合には凡そHSLの各分解能を1000くらいにすれば良いらしい事が読み取れる。勿体ぶって無いで横軸を対数にして全貌を眺めると、
となる。


loss resolution res^3 log2
10000 994 982,705,371 29.87
1000 1,305 2,221,388,030 31.05
100 1,712 5,021,408,171 32.23
10 2,247 11,350,803,948 33.40
1 2,949 25,658,290,638 34.58
0.1 3,871 58,000,110,077 35.76

この式でliner方式の目標損失に対して計算される必要な分解能、その3乗、その情報量を表に整理。情報量で考えると32bit前後に収まっているし、リアルタイムに一瞬で全てのRGB24色空間の色をHSLから全単射する必要がある!みたいなヨクワカラナイ状況でも無ければ、いやまああったとしてもGPGPUかテーブル化しておけばどうにかはなるレベルね(╹◡╹)

と、それはそうと、他にもこの実験のデータがあるのでした。
liner方式ではやはり H > L > S の順に重要で、特にSの分解能はeq.とs>>1の比較から相当低く押さえ込んでしまってもRGB24色空間の呈色に及ぼす影響は低い事が分かる。RGB24色空間の呈色であればSは1024階調もあれば十分そう。
proportional方式は一見すると穏やかじゃない(゚∀゚) l>>1とs>>1が発振している。これはRGB24色空間が離散的であるが故と考えればそれほど驚くべき不自然さではない様に思う。特にpoportional方式では極低いS値に対するHが不十分であると予測して居るから、s>>1によりRGB24色空間で有効な標本が増えたのだろうと推測。しかし、この高分解能はRGB24色空間への変換効率としては非現実的な高い分解能での話なので、とりあえず考えないで置く事にしよう(╹◡╹)

実験3: HSL色空間におけるRGB24全単射の分布確認

目的: ところでそもそもHSL色空間にRGB24の全単射ってどんな風に分布するの?って絵を確認していなかったので確認する。

ソース: https://gist.github.com/4542114/c9754e962d2acb7e89b654d6c95a375347b58e4f

結果と考察:

今回は結果データを気軽に貼り付けられないので、RAWな結果データが欲しければソースを翻訳して実行して見て欲しい。何せこの結果生成されるデータは、


  << ls
合計 1.7G
drwxr-xr-x 1 usagi users  168  1月 16 08:15 .
drwxr-xr-x 1 usagi users   92  1月 16 08:12 ..
-rw-r--r-- 1 usagi users 422M  1月 16 08:14 hsl_double_HSL192F.tsv
-rw-r--r-- 1 usagi users 422M  1月 16 08:15 hsl_double_HSL96F.tsv
-rw-r--r-- 1 usagi users 422M  1月 16 08:14 hsl_float_HSL192F.tsv
-rw-r--r-- 1 usagi users 422M  1月 16 08:15 hsl_float_HSL96F.tsv
とかあるので(;´∀`)
LH-MAIN /tmp/build/release-gcc/387
  << wc -l *        
  16777216 hsl_double_HSL192F.tsv
  16777216 hsl_double_HSL96F.tsv
  16777216 hsl_float_HSL192F.tsv
  16777216 hsl_float_HSL96F.tsv
  67108864 合計

差し当たりどれも16777216色ちゃんと生成されてます(╹◡╹)
可視化してみましょう。
gnuplot> set datafile separator "\t"gnuplot> set mapping cylindricalgnuplot> sp "hsl_double_HSL192F.tsv" every 512 using ($1*2.*pi):3:2

L軸からほぼ鉛直にS-H面を見ると一様分布に見える。RGB24色空間ははHSL色空間に置いて少なくともHS平面は一様分布となる事が伺える。つまり、RGB24→HSLではr(H)∝sは正しいと思われる。

続いてL-S面、L-H面を見る。L軸にカラーリングしておく。

gnuplot> set palette model HSV functions gray,1.,1.gnuplot> sp "hsl_double_HSL192F.tsv" every 512 using ($1*2.*pi):3:2 w d lc palette

どうもL軸には一様分布していない様に見える。l=0.5を中心とした二項分布っぽく見える。

先のソースを若干改修して100階調のヒストグラムも出力する様にしてみる。

ソース(+ヒストグラム改修版): https://gist.github.com/4542114

ヒストグラムデータ: https://gist.github.com/4544104

可視化すると、


gnuplot> pl "hist_hsl_double_HSL192F.tsv" using ($1/2**24) w lp pt 7 ps 2 lw 4
gnuplot> repl "hist_hsl_double_HSL192F.tsv" using ($2/2**24) w lp pt 7 ps 2 lw 4
gnuplot> repl "hist_hsl_double_HSL192F.tsv" using ($3/2**24) w lp pt 7 ps 2 lw 4
赤、緑、青の順にH,S,L。RGB24→HSLでは、Hは一様分布、Sは比例定数1の線形分布、Lは冪分布だコレ(・∀・)

Lについては概形から冪分布とは分かるものの、理由は思い浮かばない。とりあえず、
r(L)' = k (1 - abs( r(L)/2 - N ) / r(L)/2 ) ^ 2
k = 50333215.8368 = 2^24 / 33.34
N = [0..r(L)]
と言う事は簡単な数値解析で分かるんだけど。

とりあえず眠いので今回はここまでー(╹◡╹)
(たぶん、つづく)

参考:


  1. http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
  2. http://graph.pc-physics.com/
  3. http://ja.wikipedia.org/wiki/%E5%86%AA%E4%B9%97%E5%89%87


0 件のコメント:

コメントを投稿