写真をぼかす 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 側。変更点は
- 画像を正方形にしてみた。
- 元画像の Image コントロールと結果画像の Image コントロールを別に用意
- ぼかし量を調整するスライダーをつけてみた
- アプリケーションバーはメニューからボタンに変更(エフェクトはボタンで実行)
Visual Studio で見ると、こんな感じになります。
まずは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");
}
こんな感じになりました。
目標まではまだしばらくかかりますが、進めます。
Comments
Anonymous
June 10, 2012
すみません、C#のコードの ===================== using System.Windows.Resources; : private void btnOpen_Click(object sender, EventArgs e) ====================== この2行の間には(点々で省略されている部分には)何が書かれているのでしょうか?Anonymous
June 11, 2012
色々調べて解決しました。 Private以下、書くべき場所を間違えていました