こちらもディザ法と同じく2値の出力のみでグレースケールを表現しようとした処理です.ディザ法では各ピクセルに対する閾値は事前に決まっていましたが,誤差拡散法では1つのピクセルを処理する度に,元の値と処理後の値の誤差を未処理の周りのピクセルに影響を及ぼし,誤差を拡散しながら処理します.ディザ法の方が処理がシンプルですが,誤差拡散法の方が自然な形でグレースケールを再現することが出来ます.
誤差拡散法は画像の左上のピクセルから順に右方向に,上から下へ処理するとします.毎回ピクセルを処理するときに誤差を周りに拡散していくわけですが,例えば次のような状況で,緑色の位置のピクセルを処理するとします.このときそのピクセル値fが127より大きければ255(白)にし,小さければ0(黒)にします.
このようにするとそのピクセルにおいて,元の値と処理後の値に誤差eが発生します.次のようにして誤差を求め,f1,f2,f3,f4それぞれに反映させます.
このようにすると変更後の値が元の値より明るくなった場合,誤差が伝播し,その周りの値が減りますので全体的につりあいが取れそうです.もちろん処理中のピクセルが画像の端である場合,周りにピクセルが存在しませんので存在する場合にのみ誤差を拡散させています.それではソースコードを見てみます.
f = temp[i*img->width + j]; if(f > 127){ temp[i*img->width + j] = 255; e = f - 255; }else{ temp[i*img->width + j] = 0; e = f; } if(j != img->width-1) temp[i*img->width + j+1] += (5.0/16)*e; if(!j && i !=img->height-1) temp[(i+1)*img->width + j-1] += (3.0/16)*e; if(i !=img->height-1) temp[(i+1)*img->width + j] += (5.0/16)*e; if(j != img->width-1 && i !=img->height-1) temp[(i+1)*img->width + j+1] += (3.0/16)*e;
場合分けしながら上の式を処理しているだけです.これをループで回しながら全てのピクセルを処理します. tempはint型のポインタで,事前に領域を確保してから画像のピクセル値をコピーしています.見やすさの為にしているだけなので特に意味はありません.下のソースコードはディザ法同様カラーで処理していますが,ディザ法の結果と比べると画像がより滑らかになっているのがわかると思います.