画像の2値化の誤差拡散処理の走査を左右交互
caca.zoy.org
昨日に続いて、こちらを参考にして処理の方向を左右交互にするのを試した
昨日の記事では処理の方向は偶数行、奇数行ともに右進行だったのを、今回は奇数行を左進行にしてみる、これで処理の方向は左右交互になる
左進行時の誤差拡散
右進行とは左右対称になるような方向に拡散…で合っていると思う
効果
輝度250の画像で比較
左右交互にすると波状模様が緩和される
FloydSteinberg法+左右交互走査で誤差拡散
/// <summary> /// 誤差拡散、FloydSteinberg、PixelFormat.Gray8グレースケール画像専用 /// </summary> /// <param name="source">元画像のピクセルの輝度値</param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="stride">横1行分のbyte数</param> /// <returns></returns> private BitmapSource D1_FloydSteinberg(byte[] source, int width, int height, int stride) { int count = source.Length; byte[] pixels = new byte[count];//変換先画像用 double[] gosaPixels = new double[count];//誤差計算用 Array.Copy(source, gosaPixels, count); int p, yp;//座標 double gosa;//誤差(変換前 - 変換後) for (int y = 0; y < height; y++) { yp = y * stride; if (y % 2 == 0) { //偶数行は右進行 //->->-> // * 7 //3 5 1 // ̄16 ̄ for (int x = 0; x < width; x++) { //注目ピクセルのインデックス p = yp + x; //しきい値127.5未満なら0にする、それ以外は255にする SetBlackOrWhite(gosaPixels[p], pixels, p); //誤差拡散 gosa = (gosaPixels[p] - pixels[p]) / 16.0; if (x != width - 1) //右 gosaPixels[p + 1] += gosa * 7; if (y < height - 1) { p += stride; //下 gosaPixels[p] += gosa * 5; if (x != 0) //左下 gosaPixels[p - 1] += gosa * 3; if (x != width - 1) //右下 gosaPixels[p + 1] += gosa * 1; } } } else { //奇数行は左進行 //<-<-<- //7 * //1 5 3 // ̄16 ̄ for (int x = width - 1; x >= 0; x--) { //注目ピクセルのインデックス p = yp + x; //しきい値127.5未満なら0にする、それ以外は255にする SetBlackOrWhite(gosaPixels[p], pixels, p); //誤差拡散 gosa = (gosaPixels[p] - pixels[p]) / 16.0; if (x != 0) //左 gosaPixels[p - 1] += gosa * 7; if (y < height - 1) { p += stride; //下 gosaPixels[p] += gosa * 5; if (x != width - 1) //右下 gosaPixels[p + 1] += gosa * 3; if (x != 0) //左下 gosaPixels[p - 1] += gosa * 1; } } } } return BitmapSource.Create(width, height, 96, 96, PixelFormats.Gray8, null, pixels, stride); }
右進行と左進行の比較
奇数行は偶数行のコピペ改変
左進行だから横移動のカウンタxの値は画像の幅から1づつ減らす(191行目)
拡散方向が逆なので、注目ピクセルが端なのかチェックしている3つのif(199,207,210行目)の条件を逆にして、拡散対象のインデックス決定の増減計算の符号を逆にする(201,209,212行目)
他の誤差拡散法でも比較
あんまり変わらないねえ
違いが出やすい画像
Atkinsonは全く変化ないけど、それ以外は左右交互のほうがきれいになっている
普通の写真画像の場合
これは違いがわからないねえ、絶対誤差拡散感があればわかるかも
7,9番は左右交互のほうで波模様が出て不自然になった、これは計算を間違って書いてしまったのかなあと思って見直したけど、わかんない、こういう結果になることもあるのかも
全部同じじゃないですか!?
ゴト
両津「これが元のグレースケール画像」
ゴト
両津「白黒2値をFloydSteinberg法で誤差拡散したもの」
中川「へえー」
ゴト
両津「FloydSteinberg法+誤差拡散処理の走査を左右交互にしたもの」
ゴト
両津「JaJuNiでの誤差拡散」
ゴト
両津「JaJuNi+走査を左右交互にしたもの」
中川「全部同じじゃないですか!?」
本田「ちがいますよーっ」
両津「これだからしろうとはダメだ!もっとよく見ろ!」
両津「FloydSteinbergの左右交互走査では、ここの不自然な波模様が解消されている」
今回のアプリダウンロード
ファイル名:20200404_誤差拡散法蛇行走査.zip
github.com
画像ファイルをドロップで表示
ボタンで変換
右上のCopyボタンで変換した画像をクリップボードにコピー
画像を左クリックしている間は変換前の画像を表示
関連記事
減色パレットの色で減色時に誤差拡散のテストは2週間後
gogowaten.hatenablog.com
次回のC#記事は
gogowaten.hatenablog.com
前回のWPF記事は昨日