カメラで撮った写真に各種フィルタをかける

2012年1月25日(水)
PROJECT KySS

次に、MainPage.xamlを展開して表示される、MainPage.xaml.vbをダブルクリックしてリスト2のコードを記述します。

ロジックコードを記述する

リスト2 (MainPage.xaml.vb)

Option Strict On

ランチャーやチューザーに関するクラスの含まれる、Microsoft.Phone.Tasks名前空間をインポートします。
Imports Microsoft.Phone.Tasks

Imports System.Windows.Media.Imaging
Imports Microsoft.Phone

イメージを読み込んだり、操作したりするコントロールやクラスが含まれた、基本の名前空間であるImageToolsをインポートします。ImageTools.Filtering名前空間には、セピア、グレースケール、反転フィルタなどの画像フィルタが含まれています
Imports ImageTools
Imports ImageTools.Filtering

仮想ファイルシステムを作成および使用するための型が含まれている、System.IO.IsolatedStorage名前空間をインポートします。分離ストレージによって、安全なクライアント側のストレージが提供されます。
Imports System.IO.IsolatedStorage
曲、アルバム、再生リスト、ピクチャの列挙、再生、表示するためのクラスが含まれた、Microsoft.Xna.Framework.Media名前空間をインポートします。この名前空間をインポートしていないとMediaLibrayクラスが使用できませんので、注意してください。
Imports Microsoft.Xna.Framework.Media

Imports System.IO
  Inherits PhoneApplicationPage

  ' コンストラクター
  Public Sub New()
    InitializeComponent()
  End Sub

カメラを起動するCameraCaptureTaskクラス用メンバ変数myCameraTaskを宣言します。
  Dim myCameraTask As CameraCaptureTask

loadImage、filterImageを、Image クラスのピクセルを格納してファイルやストリームのサイズ変更、またカッティングのような操作からイメージを読み込む機能を提供するクラスであるExtendedImageクラス用メンバ変数として宣言します。
  Dim loadImage As ExtendedImage
  Dim filterImage As ExtendedImage

BitmapImageクラス用メンバ変数として、myImageを宣言します。BitmapImageクラスは、イメージを読み込むためのBitmapSourceを提供するクラスです。
  Dim myImage As BitmapImage

ContextMenuクラスの新しいインスタンス、myContextMenuオブジェクトをメンバ変数として宣言します。ContextMenuコントロールは、コントロールのコンテキストに固有の機能を公開するポップアップメニューを表示するコントロールです。このコントロールは、Silverlight for Windows Phone Toolkit - Nov 2011.msiに含まれていますので、下記URLよりダウンロードしてインストールしてください。
http://silverlight.codeplex.com/releases/view/75888
  Dim myContextMenu As New ContextMenu

新しいMenuItemクラスのインスタンスmyMenuItem1をメンバ変数として宣言します。MenuItemクラスは、ContextMenu 内に表示される個別の項目を表すクラスです。
  Dim myMenuItem1 As New MenuItem
  
MenuItemクラス型の新しいリストであるmenuItemListをメンバ変数として宣言します。
  Dim menuItemList As New List(Of MenuItem)

UIElementクラス型のオブジェクト変数myControlをメンバ変数として宣言します。UIElementクラスは、Silverlightのオブジェクトの基本クラスです。Silverlightで使用する各コントロールは、基本的に全てUIElementになります。
  Dim imageControl As UIElement

ページがアクティブになった時の処理

新しいCameraCaptureTaskのインスタンスを作成します。AddHandlerステートメントで、タスクが完了した時のCompletedイベントハンドラを追加します。Completedイベント内では完了イベントがTaskResult.OKで、正常に完了した場合は以下の処理を行います。
新しいBitmapImageのインスタンスmyImageを作成します。chooser での選択の結果は引数で渡されるので、SetSourceメソッドで、渡された画像を BitmapImage オブジェクトに格納します。Image1~Image5のSourceプロパティに、chooserで選択した画像を格納しているBitmapImageオブジェクトを指定します。Picturesで選択した画像が表示されます。ただし、Image1~Image4は非表示となっていますので、表面上はImage5の画像のみ表示されています。
BitmapImageのインスタンスmyImageで初期化された、新しいWriteableBitmapオブジェクトwbを作成します。WriteableBitmapクラスは、書き込みおよび更新が可能な BitmapSource を提供するクラスです。
新しいExtendedImageクラスのインスタンスを作成します。SetPixelsメソッドで、loadImageオブジェクトに画像のピクセル配列を設定します。書式は下記の通りです。

ImageBase.SetPixels(画像の新しいPixelWidth(0より大きい),画像の新しいPixelHeight(0より大きい), 色のバイト配列)

wb.ToByteArrayメソッドは、WriteableBitmap byte()に変換するメソッドです。[参照の追加(R)]から、WriteableBitmapEXWinPhone.dllを追加していなければ、wb.ToByteArrayメソッドが使用できませんので、注意してください。
Sepiaクラスとしてfilter変数を宣言します。新しいSepiaクラスのインスタンスを作成します。画像のピクセル配列の設定されたloadImageで初期化された、新しいExtendedImageを作成します。Sepia.Applyメソッドで、指定されたRectangleの領域で画像へのフィルタが適用されます。Applyメソッドの書式は下記の通りです。

Sepia.Apply(フィルタを適用するターゲットとなるイメージ,元のイメージ, フィルタが適用されるべき画像の領域を定義するRectangle)

Rectangleは下記の値で初期化されます。

New ImageToos.Rectangle(Rectangleの左上隅のx座標(通常0), Rectangleの左上隅のy座標(通常0),元のイメージのPixelWidth,元のイメージのPixelHeight)

フィルタの適用されたイメージを、ToBitmapメソッドでBitmapに変換し、Image1のSourceプロパティに指定します。
Inverter、Grayscale、Brightnessについても同じ処理を繰り返します。Brightnessは輝度を表し、このサンプルでは輝度に50を与えて初期化しています。値は-255~255の範囲の値を指定できます。
AddHandlerステートメントで、Image5がホールドされた時のイベントハンドラを追加します。イベントハンドラ内では、以下の処理を行います。
MenuItemクラスのオブジェクト、myMenuItem1のHeaderプロパティに「各種イメージフィルタ」と指定し、MeuItemクラス型として作成したmenuItemListリストに、AddメソッドでmyMenuItem1オブジェクトを追加します。ContextMenuクラスのオブジェクトmyContextMenuオブジェクトのItemsSourceプロパティに、myMenuItemListオブジェクトを指定します。Opacityプロパティに0.7を指定し表示されるメニューの背景を半透明化しています。ContextMenuService.SetContextMenuメソッドで、Image5オブジェクトの ContextMenu プロパティの値を設定します。
IsOpenメソッドでContextMenuを開きます。
AddHandlerステートメントでMenuItemがクリックされた時に、myMenuItem_Clickを実行するよう指定します。
  Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs)
    myCameraTask = New CameraCaptureTask
    AddHandler myCameraTask.Completed, Sub(resultSender As Object, resultArgs As PhotoResult)
              If resultArgs.TaskResult = TaskResult.OK Then
                 myImage = New BitmapImage
                 myImage.SetSource(resultArgs.ChosenPhoto)
                 Image1.Source = myImage
                 Image2.Source = myImage
                 Image3.Source = myImage
                 Image4.Source = myImage
                 Image5.Source = myImage
                 Dim wb As WriteableBitmap = New WriteableBitmap(myImage)
                 loadImage = New ExtendedImage
                 loadImage.SetPixels(myImage.PixelWidth, myImage.PixelHeight, wb.ToByteArray())
 
                 Dim filter As Sepia
                 filter = New Sepia
                 filterImage = New ExtendedImage(loadImage)
                 filter.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
                 Dim bitmap = filterImage.ToBitmap
                 Image1.Source = bitmap
                
                 Dim filter2 As Inverter
                 filter2 = New Inverter
                 filterImage = New ExtendedImage(loadImage)
                 filter2.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
                 Dim bitmap2 = filterImage.ToBitmap
                 Image2.Source = bitmap2
 
                 Dim filter3 As Grayscale
                 filter3 = New GrayscaleRMY
                 filterImage = New ExtendedImage(loadImage)
                 filter3.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
                 Dim bitmap3 = filterImage.ToBitmap
                 Image3.Source = bitmap3
 
                 Dim filter4 As Brightness
                 filter4 = New Brightness(50)
                 filterImage = New ExtendedImage(loadImage)
                 filter4.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
                 Dim bitmap4 = filterImage.ToBitmap
                 Image4.Source = bitmap4
 
          AddHandler Image5.Hold, Sub(imageSender As Object, imageArgs As System.Windows.Input.GestureEventArgs)
  
            myMenuItem1.Header = "各種イメージフィルタ"
            menuItemList.Add(myMenuItem1)
            myContextMenu.ItemsSource = menuItemList
            myContextMenu.Opacity = 0.7
            ContextMenuService.SetContextMenu(Image5, myContextMenu)
            myContextMenu.IsOpen = True
          End Sub
 
          AddHandler myMenuItem1.Click, AddressOf myMenuItem_Click
        Else
          Exit Sub
        End If
      End Sub
        MyBase.OnNavigatedTo(e)
    End Sub
  • 「カメラで撮った写真に各種フィルタをかける」サンプルプログラム

四国のSOHO。薬師寺国安(VBプログラマ)と、薬師寺聖(デザイナ、エンジニア)によるコラボレーション・ユニット。1997年6月、Dynamic HTMLとDirectAnimationの普及を目的として結成。共同開発やユニット名義での執筆活動を行う。XMLおよび.NETに関する著書や連載多数。最新刊は「Silverlight実践プログラミング」両名とも、Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。http://www.PROJECTKySS.NET/

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています