カメラでクラウディア(Webカメラと画像を合成保存)2カ月で160本作った還暦開発者が送る10のアプリ開発ノウハウ(1)(5/5 ページ)

» 2013年10月30日 18時00分 公開
[薬師寺国安,PROJECT KySS]
前のページへ 1|2|3|4|5       

「合成保存」ボタンがタップされた時の処理

 次は、このアプリの肝となる、拡大縮小、移動したクラウディアの画像を合成する処理だ。Nugetで取得したWriteableBitmapExのBiltメソッドを使用する。

Private Async Sub gouseiButton_Click(sender As Object, e As RoutedEventArgs) Handles gouseiButton.Click
        Try
            Dim myColor = Colors.White
            Dim wb1 As WriteableBitmap = New WriteableBitmap(640, 480)
            Dim wb2 As WriteableBitmap = New WriteableBitmap(81, 249)
            wb1.SetSource(Await myFile.OpenReadAsync()) ' 合成領域の画像
            wb2.SetSource(Await claudiaImage.OpenReadAsync()) ' 合成する画像
            Dim myRect1 As Rect = New Rect()
            myRect1.Width = Math.Round(81 * myTrans.ScaleX)
            myRect1.Height = Math.Round(249 * myTrans.ScaleY)
            myRect1.X = myTrans.TranslateX
            myRect1.Y = myTrans.TranslateY
            Dim myRect2 As Rect = New Rect(0, 0, 81, 249)
         ‘ このプログラムの肝。Webカメラからの画像と、拡大縮小、移動されたクラウディアの画像を合成する。
            wb1.Blit(myRect1, wb2, myRect2, myColor, WriteableBitmapExtensions.BlendMode.Alpha)
            wb1.Invalidate()
            Using myStream As Stream = wb1.PixelBuffer.AsStream
                Await myStream.FlushAsync()
                Image1.Source = myBilt1
            End Using
            Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
            Dim SubFolder = Await myFolder.CreateFolderAsync("CameraWithClaudia", CreationCollisionOption.OpenIfExists)
            Dim myID As Guid = Windows.Graphics.Imaging.BitmapEncoder.PngEncoderId
            Await WriteableBitmapSaveExtensions.SaveToFile(wb1, myFile, myID)
            Dim saveMessage As New MessageDialog("ピクチャライブラリ―のCameraWithClaudiaフォルダーに保存しました。")
            Await saveMessage.ShowAsync
            ichiranButton.IsEnabled = True
            Canvas1.Children.Clear()
            Image1.Source = Nothing
            claudiaListBox.IsEnabled = False
            gouseiButton.IsEnabled = False
        Catch
            Exit Sub
        End Try
    End Sub

 以降、上記コードの中身を詳細に見ていこう。

 まず、非同期処理で行われるためメソッドの先頭にAsyncを追加する。

 色はWhiteとしておく。ほかの色にすると、画像自体にその色のフィルターが掛かってしまうためだ。

 Webカメラで写した、台紙となる画像サイズが640×480で初期化された、WriteableBitmapオブジェクトのインスタンスwb1を作成する。

 次に、クラウディアの画像サイズ81×249で初期化された、新しいWriteableBitmapオブジェクトのインスタンス、wb2を作成する

 ストリームにアクセスしてBitmapSourceのソースイメージ(この場合、Await myFile.OPenReadAsync)を設定し、変数wb1で参照する(合成領域の画像)。同じく、変数wb2で合成する画像(クラウディア)を参照する。

 四角形の幅、高さ、および原点を示す新しいインスタンスmyRect1を作成する。myRect1の[Width]にクラウディアの拡大したWidthの値を指定する。myRect1の[Height]にクラウディアの拡大したHeightの値を指定する。myRect1の[X]と[Y]プロパティにクラウディアの移動した距離の値を指定する。

 クラウディアの幅と高さで初期化した、新しいRectのインスタンスmyRect2を作成する。

 WriteableBitmapExのBiltメソッドで合成領域(Webカメラで撮った画像)にクラウディアの画像を合成する。書式は下記の通りだ。

Wb.Bilt(destRect As Rect,Source As Media.Imaging.WritableBitMap,sourceRect As Rect,color As Windows.UI.Color,BlendMode as Media.Imaging.WriteableBitmapExtensions.BlendMode)

 BlendModeには、必ずWriteableBitmapExtensions.BlendMode.Alphaと指定する。

 Invalidateメソッドで、ビットマップ全体を再描画する。

 合成した画像の、各ピクセルの書き込み先のディレクトリバッファーのアクセスを取得し、Stream型の変数myStreamで参照する。FlushAsyncメソッドで、ストリームに対応する全てのバッファーを非同期にクリアし、バッファー内のデータをデバイスに書き込む。Image1のソースプロパティにクラウディアの画像が合成されたwb1オブジェクトを指定する。これで、Image1にクラウディアが拡大縮小され、任意の位置に配置された画像が合成表示される。

 ピクチャライブラリ―の「CameraWithClaudia」サブフォルダーにアクセスする。

 Windows.Graphics.Imaging.BitmapEncoder.PngEncoderIdで、PNG画像のグローバル一意識別子を取得して、変数myIDに格納しておく。

WinRTXamlToolkit.ImagingのWriteableBitmapSaveExtensions.SaveToFileメソッドで、合成した画像(wb1)を「yyyy年MM月dd日HH時mm分ss秒.png」形式で書き出す。WriteableBitmapSaveExtensions.SaveToFileメソッドの書式は下記だ。
WriteableBitmapSaveExtensions.SaveToFile(writeableBitmap as Windows.UI.Xaml.Media.Imageing.WriteableBitmap,output as Windows.Storages.StorageFile,encodeId as System.GUID)

 保存した旨のメッセージボックスを表示する。

 [一覧]アイコンを使用可能にし、Canvas1をクリアし、Image1に表示されていた画像を消去し、クラウディアの画像の表示されているリストボックスを使用不可とし、[合成保存]ボタンの使用を不可とする。

画像の一覧を表示する処理のロジックコード(ImageIchiranPage.xaml.vb)

 次に、[ソリューション・エクスプローラー]内のImageIchiranpage.xamlを展開して表示される、ImageIchiranPage.xaml.vbをダブルクリックしてコードを記述する。

 ここでは、コードが長くなるためコードを全部記載することは省略している。全てのコードを見る場合は、サンプルをダウンロードして「MainWindow.xaml.vb」ファイルを見ていただきたい。

    Private Async Function DataShow() As Task
        GridView1.Items.Clear()
        Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
        Dim mySubFolder = Await myFolder.CreateFolderAsync("CameraWithClaudia", CreationCollisionOption.OpenIfExists)
        myPictureFiles = Await mySubFolder.GetFilesAsync()
        If myPictureFiles.Count = 0 Then
            Dim message As New MessageDialog("画像はありません。戻ってください。")
            Await message.ShowAsync
            Exit Function
        End If
        For Each myPhotoFile In myPictureFiles
            Dim bmp As New BitmapImage
            bmp.SetSource(Await myPhotoFile.OpenSequentialReadAsync)
            Dim myImage As New Image
            myImage.Width = 640
            myImage.Height = 480
            myImage.Source = bmp
            Dim myFileName As New TextBlock
            myFileName.Text = myPhotoFile.Name
            myFileName.FontSize = 20
            myFileName.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center
            Dim myStackPanel As New StackPanel
            myStackPanel.Margin = New Thickness(3)
            myStackPanel.Children.Add(myImage)
            myStackPanel.Children.Add(myFileName)
            GridView1.Items.Add(myStackPanel)
        Next
        AddHandler GridView1.Loaded, AddressOf Me.GridView1_Loaded
    End Function

 以降、上記コードの中身を詳細に見ていこう。

 非同期処理が行われるため、メソッドの先頭にAsyncを追加する。

 GridView1内をクリアしておく。

 ピクチャライブラリ―の「CameraWithClaudia」サブフォルダーにアクセスする。GetFilesAsyncメソッドでサブフォルダー内の画像を取得し、コレクションメンバー変数「myPictureFiles」に格納しておく。画像がない場合はメッセージボックスを表示し、処理を抜ける。

 メンバー変数myPictureFiles内のファイルをmyPhotoFile変数に格納しながら、以下の処理を行う。

 新しいBitmapImageのインスタンスbmpオブジェクトを作成する。SetSourceメソッドに、「Await myPhotoFile.OpenSequentialReadAsync」と指定して、順次読み取りアクセス用のストリームを開く。

 新しいImageのインスタンスmyImageオブジェクトを作成する。[Width]に「640」、[Height]に「480」を指定し、[Source]プロパティにbmpオブジェクトを指定する。

 新しいTextBlockのインスタンスmyFileNameオブジェクトを作成する。[Text]プロパティにmyPhotoFile.Nameを指定し、拡張子を含むファイル名を指定する。文字サイズには「20」を、文字位置は「中央揃え」とする。

 StackPanelの新しいインスタンスmyStackPanelオブジェクトを作成する。[Margin]プロパティに「3」を指定して余白を設ける。AddメソッドでmyStackPanelオブジェクトにmyImageオブジェクトとmyFileNameオブジェクトを追加する。GridViewに画像と、ファイル名の追加されたmyStackPanelオブジェクトを追加する。これで、GridView1に画像の一覧が表示される。

次回は、複数画像の中から、選択した画像の拡大・縮小・回転

 今回は、ここまでだ。また次回の記事でお会いしよう。次回は複数画像の中から、選択した画像の拡大・縮小・回転させる方法を紹介する。

関連リンク

本コンテストでは、2013年9月1日〜12月1日に新たにWindowsストアに新規公開されたアプリを募集します。入賞したアプリの製作者には、総額130万円の賞金が授与されますので、ふるってご応募ください。

著者プロフィール

PROJECT KySS 薬師寺 国安(やくしじ くにやす)

1950年生まれ。フリーVBプログラマ。高級婦人服メーカーの事務職に在職中、趣味でVBやActiveXに取り組み、記事を執筆。2003年よりフリー。.NETやRIAに関する執筆多数。Windowsストアアプリも多数公開中(約270本)。

 

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。

Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。

Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。

PROJECT KySSは、1997年に薬師寺聖と結成したコラボレーション・ユニット


前のページへ 1|2|3|4|5       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。