赤、緑、青の原色のうちどれか1つのの色に注目して考えます。 ある原色の明るさが 0 〜 maxlevel の範囲(すなわち maxlevel+1通り)で 表現されているとします。 これを nlevel 通りの明るさにマップしなければならなくなったとすると、 (maxlevel+1)通りが nlevel 通りに対応づけられるので、もとの明るさを (maxlevel+1)/nlevel の長さに分割して考えればよいことになります。 すなわち、元の明るさが x であったとすると、これは 0〜 (nlevel-1) の範囲のうち x * nlevel / (maxlevel+1) 番目にマップされるわけです。
0 〜 (nlevel - 1) の範囲で i番目のレベルが持つ明るさは i * maxlevel/(nlevel-1) です。
maxlevel=255, nlevel=4の場合を考えましょう。
赤、緑、青の各原色についてそれぞれ4段階の明るさに分けると 4^3=64色必要となります。 各原色が0から255までの値を取るとすると、XColor構造体で 指定する値の計算は以下のようになります。
色の割り当て |
|
(maxlevel+1) 段階で表現された『原色の成分値 x1 』を 別のnlevel段階の値 x2 に変換するには
x2 = x1 × nlevel/(maxlevel+1)を計算します。したがって、赤(red)、緑(green)、青(blue)の値が 与えられたときにどのカラーセルを使って描画すべきかを 計算する式は以下のようになります。
中間色の参照 |
|
RGBファイルの中で赤緑青の原色値が各8bitで表現されて 並んでいるとします。 すると、320×240のRGB画像を4×4×4=64色で表示する プログラム x12.c は以下のようになります。
x12.c |
|
演習用のRGBファイルの例としては ~nitta/pro2w/tmp.rgb が 用意してあります。 しかし、できるだけ自分で画像を用意してRGB形式に変換して 使ってみることを勧めます。
ppmファイルをrgbファイルに変換するには ppm2rgb を使います。ppm2rgbの使用方法 |
|
giftopnm | gif→pnm |
ppmtogif | ppm→gif |
pnmscale | pnmファイルの大きさ変更 |
cjpeg | jpegファイルへの変換 |
djpeg | jpegファイルからの変換 |
xv | いろいろな形式を扱える |
変換例 [GIFファイル→RGBファイル] giftopnm tmp.gif | ~nitta/bin/ppm2rgb > tmp.rgb [JPEG ファイル→RGBファイル] djpeg -ppm tmp.jpg | ~nitta/bin/ppm2rgb > tmp.rgb
「多くの色を用いた画像」を少ない色で表現するには、 元の画像上の点の色を「使える色のうちで最も近い色」に 対応づけるだけでは不十分です。 元の画像にあった細かな色の変化が表現できず、 平坦に塗りつぶされてしまった画像になってしまいます。 そうならないためには、中間色を、少ない色を混ぜ合わせて 表現します。すなわち、対応づけられる色を適当な割合で 変化させる (= 『震えさせる』、ditherは「震える」という意味があります) ことにより、ある点の色が遠目には混ざりあって 元の色に近い色に見えるようにするのです。 これをディザ (dither)法といいます。
マップする色に変化を与える方法としては、
ランダム・ディザは、確率的に値を震えさせる方法です。
たとえば、0〜255の値を4段階にマップする場合を考えます。 255/(4-1)=85 なので、以下のようなマッピングを考えることができます。
0 1 2 3 ← 4段階の数値 0 85 170 255 ← 256段階の明るさを4段階にマップ元の明るさが 130 である点は、130 * 3 /255 = 1.5294... なので (整数で考えれば)1 にマップされることになります。 しかし、より原画像に近い色で表現するためには
前もってディザのパターンを用意しておき、点のXY座標によって 誤差の扱いを変える方法をオーダード・ディザといいます。 ディザのパターンは次のBayerマトリクスの4x4のものが実用上 よく利用されています。
ディザ・パターン (Bayerマトリクス) 2x2: 0 2 3 1 4x4: 0 8 2 10 12 4 14 6 3 11 1 9 15 7 13 5
たとえば、0〜255の値を4段階にマップする場合を考えましょう。 255/(4-1)=85 なので、以下のようなマッピングを考えることができます。
0 1 2 3 ← 4段階の数値 0 85 170 255 ← 256段階の明るさを4段階にマップ元の明るさが 130 である点は、130 * 3 /255 = 1.5294... なので (整数で考えれば)1 にマップされることになります。 ランダムディザのところで示した通り、 0〜CMAXの値を CSIZE 段階にマップする場合には 元の明るさ r の点は r * (CSIZE-1)/CMAX にマッピングされます。 したがって誤差は r * (CSIZE-1) /CMAX - [r * (CSIZE-1) /CMAX] となります。
しかし、より原画像に近い色で表現するためには
N×Nのディザパターンが bayer[N][N]で与えられているとすると
誤差 > bayer[x%N][y%N]/(N*N)のときに、マップされる値を +1 します。 すなわち点の位置(座標)によって誤差の扱いを変えることで、 ある確率で上下の色に振り分けるているわけです。
たとえば、0〜255の値を4段階で表すと
0 1 2 3 ← 4段階の数値 0 85 170 255 ← 256段階の明るさを4段階にマップとなります。このとき 130 という明るさを持つ点は 1.5294... にマップされ、 誤差は 1.5294 - 1.0 = 0.5294... となります。 4x4の大きさのディザパターンを使う場合は
0.5429... > dither[x%4][y%4]/16のときだけ、一つ上の値の2にマップすることにします。 計算速度の点からみると、プログラム的には、両辺に 「ディザの大きさ」を掛けて整数で計算する方がよいでしょう。
上記のクライアント(x12.c)を動作させましょう。
中間色を計算のところで Bayer's Matrixによるオーダード・ディザを 使うように変更したプログラムを作って下さい。 ファイル名は x13b.c としましょう。
x13b.c を変更して、誤差の計算を整数で演算するように工夫した プログラム x13d.c を作って下さい。
課題が完成したら x13b.c を p2r11@nw.tsuda.ac.jp へ送って下さい。 Subject は report としましょう
オプション課題ができた人は、 Subjectを option 3 として x13d.c をp2r11@nw.tsuda.ac.jpに送って下さい。
上記の Email アドレス宛に送ったメイルは http://nw.tsuda.ac.jp/cgi-bin/cgiwrap/p2r11/mailhead でヘッダ部が参照できるます。 Emailを送ったあとで、正しく提出されたかどうか確認しておいて下さい。
提出期限は来週木曜日の8:50a.m. です。