写真を加工する 5.1.2 ぼかしクラス追加

#wp7dev_jp

写真を加工する Part5.1.1 オーバーレイクラス化 でフィルタを別クラスファイルにまとめました。

そんなわけで以前作った、ガウスぼかしフィルタ を新たに追加します。

Effects/Blur.cs

基本的な作りは、オーバーレイクラス化 と同じです。

  • ぼかしではフィルタ画像を使わないので、画像の引数は1つだけです。
  • その他ぼかし半径を引数は引数で指定し、
  • 更に間引き引数付き・無しの関数を準備(引数なしの場合は間引きなし)

そのほかは以前のガウスぼかしフィルタ と基本的には変わってないです。(変数名等の変更程度)

 using System;
namespace Layer
{
    public class Blur
    {
        public static int[] effect(
            int[] input1, int width, int height, double radius)
        {
            return effect(input1, width, height, radius, 1);
        }
        public static int[] effect(
            int[] input1, int width, int height, double radius, int skip)
        {
            double blurRange = radius * 3; //ガウス分布 σ
            //ガウス分布配列作成
            double[] gaussparam = new Double[(int)blurRange + 1]; 
            for (double i = 0; i < blurRange; i++)
                gaussparam[(int)i] = Math.Exp(-i * i / (2 * radius * radius));
            int[] temp = new int[input1.Length];
            int[] result = new int[input1.Length];
            for (int pixel = 0; pixel < input1.Length; pixel++)
            {
                int ox = pixel % width;
                int oy = pixel / width;
                double gauss = 0;
                double count = 0;
                double A = 0;
                double R = 0;
                double G = 0;
                double B = 0;
                for (int x = -1 * (int)blurRange; x <= blurRange; x += skip)
                {
                    int tx = ox + x;
                    if ((tx >= 0) && (tx < width))
                    {
                        gauss = gaussparam[Math.Abs(x)];
                        uint color = (uint)input1[tx + oy * width];
                        A += (double)(color >> 24) * gauss;
                        R += (double)((color >> 16) & 0x000000FF) * gauss;
                        G += (double)((color >> 8) & 0x000000FF) * gauss;
                        B += (double)((color) & 0x000000FF) * gauss;
                        count += gauss;
                    }
                }
                A /= count;
                R /= count;
                G /= count;
                B /= count;
                temp[pixel] = 
                    ((int)A << 24) | ((int)R << 16) | ((int)G << 8) | (int)B;
            }
            //縦方向のぼかし効果処理
            for (int pixel = 0; pixel < temp.Length; pixel++)
            {
                int ox = pixel % width;
                int oy = pixel / width;
                double gauss = 0;
                double count = 0;
                
                double A = 0;
                double R = 0;
                double G = 0;
                double B = 0;
                for (int y = -1 * (int)blurRange; y <= blurRange; y += skip)
                {
                    int ty = oy + y;
                    if ((ty >= 0) && (ty < height))
                    {
                        gauss = gaussparam[Math.Abs(y)];
                        uint color = (uint)temp[ox + ty * width];
                        A += (double)(color >> 24) * gauss;
                        R += (double)((color >> 16) & 0x000000FF) * gauss;
                        G += (double)((color >> 8) & 0x000000FF) * gauss;
                        B += (double)((color) & 0x000000FF) * gauss;
                        count += gauss;
                    }
                }
                A /= count;
                R /= count;
                G /= count;
                B /= count;
                result[pixel] =
                    ((int)A << 24) | ((int)R << 16) | ((int)G << 8) | (int)B;
            }
            return result;
        }
    }
}

MainPage.xaml.cs

さて、呼び出し側からぼかしフィルタを読んで試してみます。

せっかくなので、ぼかしフィルタ+40%半透明+元画像 = ソフトフォーカス をやってみました。こんな感じです。

image

 private void btnEffect_Click(object sender, EventArgs e)
{
    //デバッグ用:時間計開始時間設定
    DateTime start = DateTime.Now;
    //【0】元画像, フィルタ画像用意
    WriteableBitmap src = new WriteableBitmap(sourceimg1, null); 
    WriteableBitmap flt = new WriteableBitmap(sourceimg2, null); 
    int w = src.PixelWidth;
    int h = src.PixelHeight;
    int[] result;
    //【1】フィルタ効果をかける
    //
    //ぼかしをかけて半透明にして元画像と合わせてソフトフォーカス
    result = Blur.effect(src.Pixels, w, h, 5, 3);
    resultimg.Opacity = 0.6;
    //オーバーレイ
    //resultimage = Overray.effect(src.Pixels, flt.Pixels, wpw, wph);
    //【2】フィルタ適応画像 → WriteableBitmap → Imageコントロールに表示
    WriteableBitmap finalwp = new WriteableBitmap(w, h);
    Buffer.BlockCopy( result, 0, finalwp.Pixels, 0, result.Length * 4);
    resultimg.Source = finalwp;
    //デバッグ用:処理時間表示
    ApplicationTitle.Text = "Photo Effect Sample : " +
        (DateTime.Now - start).TotalSeconds.ToString() + " sec";
}

構造はいたってシンプル。⓪画像を用意して、①フィルタをかけて、②画面に表示するだけ。

 

実行結果

初めが実行前の元画像、次がぼかしを使ったソフトフォーカスエフェクト(5px、間引き3)、最後は 6px、間引き5です。

image 

image image

やっぱり ぼかし半径5pxで、間引き 3 でも3秒近くかかってしまいます。計算範囲が30ドットで間引いても10ドット、10x10の計100ドットの重みづけ平均を出しているのである程度は仕方ないですが。

ぼかし系は、読み込んだ時点で、裏でこっそりやっておいた方がいいですね。

関連リンク