午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

誤差拡散法を試してみた2回め

誤差拡散

Libcaca study - 3. Error diffusion
こちらを参考にして試してみた

f:id:gogowaten:20200329154456j:plain f:id:gogowaten:20200403110150p:plain f:id:gogowaten:20200403110202p:plain f:id:gogowaten:20200403110234p:plain f:id:gogowaten:20200403110759p:plain f:id:gogowaten:20200403110814p:plain f:id:gogowaten:20200403110822p:plain f:id:gogowaten:20200403110834p:plain f:id:gogowaten:20200403110843p:plain f:id:gogowaten:20200403110849p:plain f:id:gogowaten:20200403110857p:plain f:id:gogowaten:20200403110903p:plain f:id:gogowaten:20200403110917p:plain f:id:gogowaten:20200403110925p:plain
左から
FloydSteinberg
JaJuNi(Jarvis, Judice, and Ninke)
FloydSteinbergDervatives
ShiauFan
ShiauFan2
Stucki
Burkes
Sierra
SierraTwoRow
SierraLite
Atkinson

PixelFormats.BlackWhite
一覧画像
f:id:gogowaten:20200403124555p:plain
こっちのほうが見やすいかな

f:id:gogowaten:20200403124628p:plain


使ったアプリ
f:id:gogowaten:20200403131921p:plain
表示できるのはアプリに埋め込んだ画像のこれだけ
一番上のCopyボタンは2値化画像をクリップボードへコピーする
その下のPixelFormatsBlackWhiteはFormatConvertedBitmapクラスを使ってピクセルフォーマットをBlackWhiteに変換する
それ以下のボタンはそれぞれの方法で誤差拡散
2値画像を左クリック中は元のグレースケール画像を表示する

ファイル名:20200402_誤差拡散2値.zip

github.com

普通の画像で
f:id:gogowaten:20200403124043p:plain
画像サイズが大きすぎてはてなブログだと縮小表示になるから、右クリックメニューから別のタブで開かないと正しく表示されないねえ

f:id:gogowaten:20200403124055p:plain
これは正しく等倍表示されている

輝度250のグレースケール画像
f:id:gogowaten:20200403123622p:plain


輝度128のグレースケール画像
f:id:gogowaten:20200403125714p:plain
拡散範囲が広いものほどゴワゴワする感じ、AtkinsonとPixelFormatsBlackWhiteは均一になった


/// <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;//誤差(変換前 - 変換後)

    //  * 7
    //3 5 1
    // ̄16 ̄
    for (int y = 0; y < height; y++)
    {
        yp = y * stride;
        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;
            }
        }
    }
    return BitmapSource.Create(width, height, 96, 96, PixelFormats.Gray8, null, pixels, stride);
}

/// <summary>
/// しきい値127.5で 0 or 255、127.5未満は0、127.5以上は255に置き換える
/// 127.49999999999999999...は0、127.5以上は255だから、整数の場合は127.5を四捨五入した128未満が0、それ以外は255にすればいい?
/// </summary>
/// <param name="value">対象の値</param>
/// <param name="pixels">0 or 255を入れる配列</param>
/// <param name="p">配列のIndex</param>
private void SetBlackOrWhite(double value, byte[] pixels, int p)
{
    if (127.5 > value)
        pixels[p] = 0;
    else
        pixels[p] = 255;
}




関連記事
次回のWPF記事は翌日

gogowaten.hatenablog.com

前回のWPF記事は昨日

gogowaten.hatenablog.com

1ヶ月後
gogowaten.hatenablog.com ガンマ補正したほうが元の画像に近くなる

前回の誤差拡散は2年前

gogowaten.hatenablog.com これと

gogowaten.hatenablog.com