写真をぼかす Part 3.1 いったん整理

#wp7dev_jp

さて、いったん今後の作業のためにアプリを整理します。 まずは 画像ファイルを追加します。

ファイルの追加

プロジェクトに、「Images:フォルダを追加して、そこに以下のファイルをコピーします。

  • フォルダ: C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\dark
    • ファイル1:appbar.folder.rest.png
    • ファイル2:appbar.favs.rest.png

コピーしたらファイルのプロパティを以下のように設定。

  • ビルドアクション: コンテンツ
  • 出力ディレクトリにコピー:新しい場合はコピーする

XAML

そして UI 側。変更点は

  1. 画像を正方形にしてみた。
  2. 元画像の Image コントロールと結果画像の Image コントロールを別に用意
  3. ぼかし量を調整するスライダーをつけてみた
  4. アプリケーションバーはメニューからボタンに変更(エフェクトはボタンで実行)

Visual Studio で見ると、こんな感じになります。

image

まずはXaml。

 <Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid x:Name="ContentPanel" >
        <Image Name="sourceimg" Stretch="UniformToFill" Height="480" />
        <Image Name="resultimg" Stretch="UniformToFill" Height="480"/>
        <Slider  Name="radius" VerticalAlignment="Bottom" Minimum="0" Value="5" />
    </Grid>
</Grid>
<!--ApplicationBar の使用法を示すサンプル コード-->

<phone:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
        <shell:ApplicationBarIconButton 
            IconUri="/Images/appbar.folder.rest.png" Text="画像読込" 
            x:Name="btnOpen" Click="btnOpen_Click" />
        <shell:ApplicationBarIconButton 
            IconUri="/Images/appbar.favs.rest.png" Text="エフェクト" 
            x:Name="btnEffect" Click="btnEffect_Click" />
    </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

C#

そしてコード側。

btnOpen_Click と、task_Completed は画像を読み込むためのもの。

Effect 関数内でガウスぼかしのために、元画像→横ぼかし→縦ぼかし→適応後画像 の処理をしています。

 

 using Microsoft.Phone.Tasks;
using System.Windows.Media.Imaging;

using System.Windows.Resources;
        :
private void btnOpen_Click(object sender, EventArgs e)
{
    PhotoChooserTask task = new PhotoChooserTask();
    task.Completed += new EventHandler<PhotoResult>(task_Completed);
    task.Show();
}
void task_Completed(object sender, PhotoResult e)
{
    if (e.TaskResult == TaskResult.OK)
    {
        BitmapImage bmp = new BitmapImage();
        bmp.SetSource(e.ChosenPhoto);
        sourceimg.Source = bmp;
        resultimg.Source = null;
    }
}
private void btnEffect_Click(object sender, EventArgs e)
{
    Effect();
}
private void Effect()
{
    WriteableBitmap sourcewp = new WriteableBitmap(sourceimg, null); //元画像用
    int wpw = sourcewp.PixelWidth; //画像の幅
    int wph = sourcewp.PixelHeight; //画像の高さ
    WriteableBitmap tempwp = new WriteableBitmap(wpw, wph); //横方向ぼかし結果保存用
    WriteableBitmap finalwp = new WriteableBitmap(wpw, wph); //最終結果保存用
    double blur = radius.Value ; // ガウスぼかし半径
    double blurRange = blur * 3; //ガウス分布 σ
    Double[] gaussparam = new Double[(int)blurRange + 1]; //ガウス分布係数
    //ガウス分布配列作成
    for (double i = 0; i < blurRange; i++)
        gaussparam[(int)i] = Math.Exp(-i * i / (2 * blur * blur));
    //デバッグ用:時間計開始時間設定
    DateTime start = DateTime.Now;
    //横方向のぼかし効果処理
    for (int pixel = 0; pixel < sourcewp.Pixels.Length; pixel++)
    {
        int ox = pixel % wpw;
        int oy = pixel / wpw;
        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++)
        {
            int tx = ox + x;
            if ((tx >= 0) && (tx < wpw))
            {
                gauss = gaussparam[Math.Abs(x)];
                uint color = (uint)sourcewp.Pixels[tx + oy * wpw];
                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;
        tempwp.Pixels[pixel] = ((int)A << 24) | ((int)R << 16) | ((int)G << 8) | (int)B;
    }
    //縦方向のぼかし効果処理
    for (int pixel = 0; pixel < tempwp.Pixels.Length; pixel++)
    {
        int ox = pixel % wpw;
        int oy = pixel / wpw;
        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 += 3)
        {
            int ty = oy + y;
            if ((ty >= 0) && (ty < wph))
            {
                gauss = gaussparam[Math.Abs(y)];
                uint color = (uint)tempwp.Pixels[ox + ty * wpw];
                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;
        finalwp.Pixels[pixel] = ((int)A << 24) | ((int)R << 16) | ((int)G << 8) | (int)B;
    }
    //作成された画像を元画像として表示
    resultimg.Source = finalwp;
    //処理時間表示
    MessageBox.Show((DateTime.Now - start).TotalSeconds.ToString() + " sec");
}

こんな感じになりました。

image

目標まではまだしばらくかかりますが、進めます。