私は今、研究で負の値を必要とするハイダイナミックレンジな特殊なマップを必要としています。
一般的な画像でも2の補数を負の値と考えれば、負の値を格納することは可能です。
HDRIなどを除く一般的な画像形式は1画素辺り1byteのデータ(256階調)を格納できるので、負の値と正の値を格納するときは次のように考えることができます。
8 → 0000 0000 0000 0000 0000 0000 0000 0100 -8 → 1111 1111 1111 1111 1111 1111 1111 1000 |
ただし、この方法で負の値を格納すると-128から127までの値しか保存することはできません。
これではダイナミックレンジが狭すぎるので、今まではただ単にテキストデータで1画素ごとに保存していました。例えば、
200
-30
4
40
12
-7
30
といったように改行を区切り文字にして、画素値をテキスト形式で保存していきました。
ですが、大量のシーケンスを書き出すと相当なデータ量となってしまうため、ファイルシステムを圧迫してしまいます。
そこで、このデータを独自圧縮形式で圧縮するプログラムを作ることにしました。
アルゴリズムは単純です。使用している領域のみ取り出してバイナリ形式で保存するというだけです。
つまり、ダイナミックレンジがフレキシブルな画像を作るのです。
具体的には次のようにします。
画像中の最小値Dminと最大値Dmaxを探索し、次式で必要なデータ幅Rを求めます。
R = Dmax - Dmin
Rに必要なビット幅を1画素分の視差データの格納単位としてデータを保存します。
画像のヘッダーには画像解像度と1画素辺りのデータ格納単位、画素値の最大値と最小値を記録しておき、読み込みのときにそれらのデータを元に画像を復元します。
ダイナミックレンジは画像により次のように変更することができます。
1bit → 2階調
2bit → 4階調
3bit → 8階調
4bit → 16階調
5bit → 32階調
6bit → 64階調
7bit → 128階調
8bit → 256階調
9bit → 512階調
...
例えば、Dmax =10、Dmin =-10だった場合、Rは20となり。 必要なビット幅は5bit(32階調)となります。
ちなみに、テキストだと1文字当たり1byte(8bit)のデータを割り当てることになるので、
文字数×8bit
のデータ量が必要になります。
例えば、もしある画素に格納されている値が200だとしたら、3文字+区切り文字が必要なので31bit使用することになります。
これでは無駄がかなり多いです。
またpgmのようにバイナリ形式で保存したとしても、ダイナミックレンジが8bit固定になってしまい、8bit未満しか使っていない場合に無駄が出ます。
その上、一般的な画像形式では1チャンネル辺り256階調以上の階調数には対応できません。
この圧縮を行えば、画像に応じた無駄のないダイナミックレンジを利用でき、かつ可変ダイナミックレンジが8bitを超える画像の保存にも対応してくれるという利点があります。
ある意味、HDRIとも言えます。
実際にプログラムを作成して利用してみると、今までのテキストデータのときよりもデータを1/3以下に削減することができました。
このように、一般的に利用されいている画像形式は全てのシチュエーションにおいて万能ではないため、目的によっては単純なアルゴリズムで最適化したやった独自のデータ形式を扱う方が、より効果を発揮する場合があるのです。