午後わてんのブログ

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

8色に減色でも誤差拡散法を試してみた

 
昨日の続き
カラー画像で誤差拡散
 
アプリダウンロード先
ここの20180223_.8.zipがそれ
 
イメージ 1
できた
左から
元の画像
右隣への誤差拡散法
FloydSteinberg
FloydSteinberg(蛇行)
SierraLite
JaJuNi
Atkinson
以前試したときはうまく書けなかったけど、昨日までの白黒をカラー版にしてみたらうまくできた
 
 
 
HSVの赤の画像
イメージ 2
 
 
イメージ 3
JaJuNiとAtkinsonは色の境界、輪郭がはっきりするから電線が目立つ感じ
 
 
 
イメージ 4
 
 
図形
イメージ 5
RGB(255_244_240)
 
イメージ 6
Atkinson消えた
蛇行のFloydSteinbergとJaJuNiがいいねえ、縞模様が出ていない
 
/// <summary>
/// PixelFormat.Pbgra32のBitmapSourceを8色に減色する
/// 8色はRGBそれぞれを閾値127.5で0か255にするので白、黒、赤、緑、青、黄色、水色、赤紫
/// ディザリング方式はFloydSteinberg
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
private BitmapSource ErrorDiffusionFloydSteinberg(BitmapSource source)
{
    var wb = new WriteableBitmap(source);
    int h = wb.PixelHeight;
    int w = wb.PixelWidth;
    int stride = wb.BackBufferStride;
    var pixels = new byte[h * stride];
    wb.CopyPixels(pixels, stride, 0);//byte配列にCopyPixel
    //float配列作成してコピー
    float[] iPixels = new float[pixels.Length];
    for (int i = 0; i < iPixels.Length; ++i)
    {
        iPixels[i] = pixels[i];
    }
    long p = 0, pp = 0;//判定中ピクセルの配列の中での位置
    float gosa = 0;//誤差記録用もfloat
    for (int y = 0; y < h; ++y)
    {
        for (int x = 0; x < w; ++x)
        {
            p = y * stride + (x * 4);//PixelFormat.Pbgra32の色の並びはBGRA
            for (int i = 0; i < 3; ++i)//0から2までの3ループはBGR
            {
                pp = p + i;
                gosa = 0;//誤差をリセット
                if (iPixels[pp] < 127.5f)//127.5未満なら0
                {
                    gosa = iPixels[pp];//誤差記録
                    iPixels[pp] = 0;
                }
                else//127.5以上なら255
                {
                    gosa = (iPixels[pp] - 255f);//誤差記録
                    iPixels[pp] = 255;
                }

                //誤差拡散、Floyd Steinberg式
                if (pp + 4 < pixels.Length && x < w - 1)
                {
                    iPixels[pp + 4] += (gosa / 16f) * 7f;//右隣+誤差(誤差拡散)
                }
                if (y < h - 1)//1行下
                {
                    if (x != 0)
                    {
                        iPixels[pp + stride - 4] += (gosa / 16f) * 3f;//左下
                    }

                    iPixels[pp + stride] += (gosa / 16f) * 5f;//真下

                    if (x < w - 1)
                    {
                        iPixels[pp + stride + 4] += (gosa / 16f) * 1f;//右下
                    }
                }
            }
        }
    }
    //byte配列に戻す
    for (int i = 0; i < pixels.Length; ++i)
    {
        pixels[i] = (byte)(iPixels[i]);
    }
    wb.WritePixels(new Int32Rect(0, 0, w, h), pixels, stride, 0);
    return wb;
}
 

昨日の白黒とほとんど同じで、違うのは色を変えたところだけ
白黒は色の情報が明るさだけだったのがカラーではRGBの3つになったので
それぞれに対して誤差拡散するので3ループしている。
PixelFormat.Pbgra32は1ピクセル4byteで色の並びはBGRAなので
右隣のピクセルに誤差拡散するときは4byte先になるので元のindex+4に値を足す。
左なら-4、2つ右なら+8なので
他の誤差拡散法も昨日のコピペ改変
 

画像ファイルを指定したPixelFormatのBitmapSourceで取得するのはいつものこれ
FormatConvertedBitmapをつかってPixelFormatを変換しているだけ

private BitmapSource GetBitmapSourceWithChangePixelFormat2(
    string filePath, PixelFormat pixelFormat, double dpiX = 0, double dpiY = 0)
{
    BitmapSource source = null;
    try
    {
        using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            var bf = BitmapFrame.Create(fs);
            var convertedBitmap = new FormatConvertedBitmap(bf, pixelFormat, null, 0);
            int w = convertedBitmap.PixelWidth;
            int h = convertedBitmap.PixelHeight;
            int stride = (w * pixelFormat.BitsPerPixel + 7) / 8;
            byte[] pixels = new byte[h * stride];
            convertedBitmap.CopyPixels(pixels, stride, 0);
            //dpi指定がなければ元の画像と同じdpiにする
            if (dpiX == 0) { dpiX = bf.DpiX; }
            if (dpiY == 0) { dpiY = bf.DpiY; }
            //dpiを指定してBitmapSource作成
            source = BitmapSource.Create(
                w, h, dpiX, dpiY,
                convertedBitmap.Format,
                convertedBitmap.Palette, pixels, stride);
        };
    }
    catch (Exception)
    {

    }

    return source;
}
 
コード全部
こっちはログアウトしてからアクセスしたらログインを促された
自分しか見れないのかな、わかんね
 
gogowaten/wpf_test: 20160611create
こっちは誰でも見れるみたいでログアウト状態でも見れた
GitHubを使ったのは今回が初めてのようなものなんだけど、アカウント自体は2年前に作っていたんだなあ
使い方わかんないけどファイルのドラッグアンドドロップでアップロードはできた
VisualStudioと連携できればラクなんだけどなあ
 
イメージ 7
実行ファイルも置いてみたけど.exeってあるのコワイw
MainWindow.xamlがデザイン画面で
MainWindow.xaml.csがコード
 
 
 
関連記事
1ヶ月前
WPF、普通の写真画像を8色に減色 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15342796.html
 
3日前
WPF、8色への減色でディザパターンを変更して遊ぶアプリ ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15381645.html
 
 
 
 
前回は1日前
FloydSteinberg他いくつかの誤差拡散を試してみた、白黒2値をディザリング ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15384380.html