Leap Motionで画像のトリミングと保存を行うためのサンプルプログラムを作る(2ページ目)
メンバー変数の宣言
次にメンバー変数を宣言します。
今回はWin32 APIを使用するためにWin32 APIの宣言も行います。下記のリスト3の部分がWin32 APIに関する宣言か所になります。
リスト3 (Win32 APIに関する宣言)
Private Declare Function SetCursorPos Lib "user32" (x As Integer, y As Integer) As Boolean
Private Declare Function apimouse_event Lib "user32" Alias "mouse_event" (ByVal dwFlags As Int32, ByVal dx As Int32, ByVal dy As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo As Int32) As Boolean
Private Const MOUSEEVENTF_MOVE = &H1
Private Const MOUSEEVENTF_LEFTDOWN = &H2
Private Const MOUSEEVENTF_LEFTUP = &H4
新しいControllerクラスのインスタンスであるleapメンバー変数を宣言します。次に、インク・ストローク(=System.Windows.Ink名前空間のStrokeクラスで表現される、WPF上でのインクの線)の外観を指定する新しいDrawingAttributesクラス(System.Windows.Ink名前空間)のインスタンスである「touchIndicatorメンバー変数」を宣言します。デジタイザーとスタイラスから収集された単一のデータ・ポイントを表すStylusPoint構造体の「touchPointメンバー変数」を宣言します。
次にRectangleクラス型の「rectメンバー変数」を宣言します。また、System.Wiondows.Pointクラスからの「pメンバー変数」を宣言します。切り出した画像を保存するフォルダ名を格納する「savePathメンバー変数」を宣言します。
そのほかの必要なメンバー変数も宣言しています(リスト4)。
リスト4 メンバー変数の宣言(MainWindow.xaml.vb)
Private leap As New Controller
Private touchIndicator As New DrawingAttributes
Public touchPoint As StylusPoint
Private rect As Rectangle
Private p As System.Windows.Point
Private savePath As String
Private windowWidth As Double = 1920
Private windowHeight As Double = 1080
Private x As Integer
Private y As Integer
Private tx As Double
Private ty As Double
Private FingersCount As Integer
MainWindow_Loadedメソッドの処理
MainWindow_Loadedメソッド(=メイン・ウィンドウのLoadedイベントのハンドラー)では、MainWindowが読み込まれたときの処理を実装します。
メンバー変数savePathに切り出した画像を保存するフォルダを指定します。
指定したフォルダが存在しなかった場合は、CreateDirectoryメソッドでフォルダを作成します。
inkCanvas1のEditingMode(ユーザー編集モードの設定)プロパティに、InkCanvasEditingMode.None(ペンがInkCanvasにデータを送信する時に、アクションが実行されないようにする)を指定します。
AddHandlerステートメントを使って、構成ツリーのオブジェクトがレンダリングされる直前に発生する「CompositionTarget.Renderingイベント」に対するイベント・ハンドラーとしてUpdateメソッドを指定します(※Updateメソッドの実装内容は後述)。
インク・ストロークの外観を表す、DrawingAttributesオブジェクトのインスタンス「touchIndicator」のWidthプロパティとHeightプロパティに、それぞれ「20」を指定します。スタイラスの形状を指定するStylusTipプロパティに「StylusTip.Ellipse」を指定して円形とします。Leap Motionの上で指をかざすと、かざした指の本数に応じて20px(px=ピクセル)の円が表示されるようになります(リスト5)。
リスト5 MainWindowが読み込まれたときの処理を行うMainWindow_Loadedメソッドの実装内容(MainWindow.xaml.vb)
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
savePath = "C:\LeapmotionTrimmingImage" ' 切り出した画像を保存するフォルダ
If Directory.Exists(savePath) = False Then
Directory.CreateDirectory(savePath)
End If
inkCanvas1.EditingMode = InkCanvasEditingMode.None
AddHandler CompositionTarget.Rendering, AddressOf Update ' Updateイベント・ハンドラ—を実行する
touchIndicator.Width = 20
touchIndicator.Height = 20
touchIndicator.StylusTip = StylusTip.Ellipse ' 20pxの円が表示される
End Sub
Updateメソッドの処理
次は、CompositionTarget.Renderingイベント・ハンドラーであるUpdateメソッドの処理です。
まず、上記のコードを実装した段階で、「Update」の位置に[エラー修正のオプション]というスマート・タグが表示されるので、そのタグのメニューから['ChangeBackgroundLeapMotion.MainWindow' に 'Update' のメソッド スタブを生成]をクリックすると、Updateメソッドのひな型が追加されます。次に、そのメソッド内を実装していきます。
「paintCanvas」という名前のInkPresenter内をクリアします。この処理を行っていないと、Updateメソッドは常に呼び出されているため、円を画面上で動かすと、円の軌跡が残ったまま表示されてしまいます。そのため、InkPresenter内をクリアする必要があります。
Leap Motionのフレームを表すFrame型(Leap名前空間)の変数「frame」を宣言します。InteractionBox型(Leap名前空間)の変数「interactionBox」を宣言し、そこにleap.Frame.InteractionBoxプロパティからInteractionBoxオブジェクトを取得します。InteractionBoxオブジェクトは、Leap Motionで認識できる稼働範囲となります。InteractionBoxオブジェクトを使用することで、指やツール(=ペンなど)の位置を実際のディスプレイの座標系に変換できます(リスト6)。
詳細な図については、「Leap Motionでのタッチ操作はどう開発するのか?」を参照してください。
リスト6 指やツールの位置を実際のディスプレイの座標系に変換する(MainWindow.xaml.vb)
Private Sub Update(sender As Object, e As EventArgs)
paintCanvas.Strokes.Clear()
windowWidth = Me.Width
windowHeight = Me.Height
Dim frame As Leap.Frame = leap.Frame
Dim interactionBox As InteractionBox = leap.Frame.InteractionBox
End Sub
Leap.Frame.Pointablesプロパティで得られるPointableListオブジェクト内を変数「Pointable」で反復処理しながら、1つずつPointableオブジェクトを処理し、それぞれのタッチ位置を取得していきます。
interactionBoxオブジェクトのNormalizePointメソッドに引数としてPointable.StabilizedTipPositionプロパティ値を渡し、ポインター上の位置を取得します。
変数「windowWidth」と「windowHeight」で表されたクライアント領域のウィンドウがある場合、以下のリスト7で示す計算式を使用してこのウィンドウ内のタッチ・ポイントの2D座標を得ることができます。
リスト7 ウィンドウ内のタッチ・ポイントの2D座標を得るコード(MainWindow.xaml.vb)
Private Sub Update(sender As Object, e As EventArgs)
……コード略……
For Each Pointable As Pointable In leap.Frame.Pointables
Dim normalizedPosition As Leap.Vector = interactionBox.NormalizePoint(Pointable.StabilizedTipPosition)
tx = normalizedPosition.x * windowWidth
ty = windowHeight - normalizedPosition.y * windowHeight
touchPoint = New StylusPoint(tx, ty) ' ウィンドウ内のタッチ・ポイントの位置を取得する
……コード略(後述)……
Next
End Sub
さらに、上記のFor Eachステートメントの一番下に次のリスト8を追記して、ディスプレイ上に円形のタッチ・ポイントを表示します。
リスト8 ディスプレイ上にタッチ・ポイントを表示する処理(MainWindow.xaml.vb)
For Each Pointable As Pointable In leap.Frame.Pointables
……コード略(前述)……
Dim tips As New StylusPointCollection(New StylusPoint() {touchPoint})
Dim touchStroke As New Stroke(tips, touchIndicator)
paintCanvas.Strokes.Add(touchStroke)
Next
- この記事のキーワード