写真をぼかす 改め加工する Part 5 レイヤー合成
#wp7dev_jp
さて、これまで写真をぼかすことをやってきましたが、今回から別のネタで進めてみます。
今回からトライするのは、レイヤー機能です。Photoshop に搭載しているフォトレタッチの重要な機能で、1つの画像に2つ目の画面をいろいろな効果を付けて合成します。
今回は、まず乗算を実装してみます。
ファイルの追加
プロジェクトに、「Images:フォルダを追加して、そこに以下のファイルをコピーします。
- フォルダ: C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\dark
- ファイル1:appbar.folder.rest.png
- ファイル2:appbar.favs.rest.png
コピーしたらファイルのプロパティを以下のように設定。
- ビルドアクション: コンテンツ
- 出力ディレクトリにコピー:新しい場合はコピーする
それから480X480の元画像とマスク用画像を用意しておきます(Source.jpg, Mask.png)
こちらも、Images フォルダにコピーしておきましょう。
XAML
さて、UI を作ります。こんなUIになります。
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="Photo Effect Sample "
Style="{StaticResource PhoneTextNormalStyle}"
FontFamily="Segoe WP Bold" />
<TextBlock x:Name="PageTitle" Text="Layer Effect"
Margin="9,-7,0,0"
Style="{StaticResource PhoneTextTitle1Style}"
FontFamily="Segoe WP Light" />
</StackPanel>
<!--ContentPanel - 追加コンテンツをここに入力します-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"
Height="480">
<Image Name="sourceimg2" Stretch="UniformToFill" Height="480"
Source="/Layer;component/Images/Mask.png" />
<Image Name="sourceimg1" Stretch="UniformToFill" Height="480"
Source="/Layer;component/Images/Source.jpg"/>
<Image Name="resultimg" Stretch="UniformToFill" Height="480" />
</Grid>
</Grid>
<!--ApplicationBar の使用法を示すサンプル コード-->
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton
IconUri="/Images/appbar.folder.rest.png" Text="画像"
x:Name="btnOpenPict" Click="btnOpenPict_Click" />
<shell:ApplicationBarIconButton
IconUri="/Images/appbar.favs.rest.png" Text="エフェクト"
x:Name="btnEffect" Click="btnEffect_Click" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
C#
さて、コード側です。といってもぼかし処理と変わりません。
乗算はその名の通り、ピクセル同士の掛け算をします。
式は 結果=元画像xマスク画像 / 255 これを各ポイントのRGBそれぞれに配置します。
元画像に対してマスク画像を掛け算して、結果としてちょっと暗くなります。
private void btnOpenPict_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);
sourceimg1.Source = bmp;
}
}
private void btnEffect_Click(object sender, EventArgs e)
{
WriteableBitmap sourcewp1 = new WriteableBitmap(sourceimg1, null); //元画像用
WriteableBitmap sourcewp2 = new WriteableBitmap(sourceimg2, null); //元画像用
int wpw = sourcewp1.PixelWidth;
int wph = sourcewp2.PixelHeight;
WriteableBitmap finalwp = new WriteableBitmap(wpw, wph); //最終結果保存用
//デバッグ用:時間計開始時間設定
DateTime start = DateTime.Now;
for (int pixel = 0; pixel < sourcewp1.Pixels.Length; pixel++)
{
uint color1 = (uint)sourcewp1.Pixels[pixel];
uint color2 = (uint)sourcewp2.Pixels[pixel];
uint A1 = (color1 >> 24);
uint R1 = ((color1 >> 16) & 0xFF);
uint G1 = ((color1 >> 8) & 0xFF);
uint B1 = ((color1) & 0xFF);
uint A2 = (color2 >> 24);
uint R2 = ((color2 >> 16) & 0xFF);
uint G2 = ((color2 >> 8) & 0xFF);
uint B2 = ((color2) & 0xFF);
uint A = A1;
uint R = 0;
uint G = 0;
uint B = 0;
// 乗算
R = R1 * R2 / 255;
G = G1 * G2 / 255;
B = B1 * B2 / 255;
finalwp.Pixels[pixel] =
((int)A << 24) | ((int)R << 16) | ((int)G << 8) | (int)B;
}
//作成された画像を元画像として表示
resultimg.Source = finalwp;
ApplicationTitle.Text = "Photo Effect Sample : " +
(DateTime.Now - start).TotalSeconds.ToString() + " sec";
//処理時間表示
}
さて、実行してみます。 元の画像にマスク画像を乗算した結果です。マスク画像を変えると別の効果も楽しめます。
処理時間も0.1秒かからないのでかなりいいですね。あとは、このフィルタの処理部分を変えていけばいろいろ出来そうです。
関連リンク