ハーフトーン処理とは黒と白つまり輝度が0と255の色だけを用いてハーフトーン(中間色)を表現しようという技術で,2値しか出力できない表示装置でなんとかグレースケールを表現しようとしたものです.具体的には目の錯覚というか,点の密度が大きいところは濃く見え,小さいところは薄く見える事を利用しています.
ディザ法とはハーフトーン処理の技術の1つで,グレースケールの画像を小さいブロックに分割し,それにマスクを掛けて閾値を越えたピクセルを白,下回ったものを黒というように処理しています.ディザ法において閾値のパターンはいろいろあり,分割するブロックの大きさもいろいろあるようですが,今回4×4のブロックに分け,Bayer型のパターンを使う事にします.
4×4のマス目の中に0から15までの値があります.また,画像の方も4×4のブロックに分割しているので,全く同じ大きさです.ですから対応するパターンを閾値と考えます.ただし,輝度は256階調なのでそれに合わせるためにパターンの値を16倍して8を足します.例えば4×4のブロックのピクセルが全て128だったとしたら次のようになります.
以上がディザ法の説明ですが,実装するにあたって実際に画像を分割する必要はありません. x,yそれぞれの座標を4で割った余りが比較すべきパターンの座標と考えれば良いです.例えば(34, 133)の座標であれば4で割ったあまりは(2, 1)ですので14に対応します.それではソースコードを見てみます.
int bayerpattern[] = { 0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; int i, j; for(i=0; i<img->height; i++){ for(j=0; j<img->width; j++){ if((bayerpattern[(i%4)*4 + (j%4)]*16 + 8) <= img->rgb[i*img->width + j].r){ img->rgb[i*img->width + j].r = img->rgb[i*img->width + j].g = img->rgb[i*img->width + j].b = 255; }else{ img->rgb[i*img->width + j].r = img->rgb[i*img->width + j].g = img->rgb[i*img->width + j].b = 0; } } }
比較しているだけなので,特に難しいところは無いと思います.
ディザ法の説明は以上ですが,グレースケールではなくカラー画像に対してディザ法を適用すると面白い結果が得られます.RGBそれぞれに対してハーフトーン処理を行うと,RGBそれぞれの値は0か255しか取らないので, 2×2×2で合計8色しか使っていないにも関わらず,意外と質は低下しません.これを利用してフルカラー画像を8色に減色することができます.減色を行うことでそれまで1ピクセルを24ビットで表していたのが, 3ビットで表現できるようになり,画像のサイズを小さくすることができます.ただし,本プログラムではビット数は減らしていないため,残念ながらサイズは小さくなりません.