Leap Motionで画像のトリミングと保存を行うためのサンプルプログラムを作る
次にLeap Motionのタッチ処理になります。タッチのイメージは次の図3のようなイメージです。
Updateメソッド(ホバー)の処理
手前側が「ホバー状態(hovering)」、奥側が「タッチ状態(touching)」を表わします。空間の範囲は前後「1」〜「-1」となっています。
まずホバーの場合は、表示されている円がBlueの色になります。タッチ・ポイントの位置をメンバー変数「x」と「y」に格納します。
Win32 APIのSetCursorPos(touchPoint.X, touchPoint.Y)と指定します。タッチ・ポイントの位置とマウスカーソルの位置が同じ位置に表示されます。
apimouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)と指定して、マウスの左ボタンを外した状態にします。
画面に表示されている指の数をleap.Frame.Fingers.Countプロパティで取得して、メンバー変数「FingersCount」に格納しておきます(リスト9)。
リスト9 ホバー時の処理(MainWindow.xaml.vb)
For Each Pointable As Pointable In leap.Frame.Pointables ……コード略(前述)…… If Pointable.TouchDistance > 0 AndAlso Pointable.TouchZone <> Global.Leap.Pointable.Zone.ZONENONE Then touchIndicator.Color = Colors.Blue x = 0 y = 0 x = touchPoint.X y = touchPoint.Y SetCursorPos(touchPoint.X, touchPoint.Y) apimouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0) FingersCount = leap.Frame.Fingers.Count' 表示されている指の本数を取得して、メンバ変数FingersCountに格納しておく ……コード略(続きは後述)…… End If Next
次にタッチした処理になります。タッチした場合は、表示されている円が赤に変わります。
Updateメソッド(タッチ)の処理
指が1本認識されている場合は、SetCursorPos(touchPoint.X, touchPoint.Y)と指定して、タッチ・ポイントとカーソルの位置を同じ位置に表示します。
apimouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, 0) apimouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
と指定して、マウスを動かした処理と、マウスの左ボタンを押した処理を行います。
タッチ以外の処理ではタッチ・ポイントの色がGoldになり、
SetCursorPos(touchPoint.X, touchPoint.Y) apimouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
と指定します。
具体的にはリスト10のコードになります。
リスト10 タッチとタッチ以外の処理
If Pointable.TouchDistance > 0 AndAlso Pointable.TouchZone <> Global.Leap.Pointable.Zone.ZONENONE Then ……コード略(前述)…… ElseIf Pointable.TouchDistance <= 0 Then touchIndicator.Color = Colors.Red If FingersCount = 1 Then SetCursorPos(touchPoint.X, touchPoint.Y) ' 指が1本認識されている場合は、タッチ・ポイントとカーソルの位置を同じ位置に表示する。 apimouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, 0) apimouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0) End If 'タッチ対象外 Else touchIndicator.Color = Colors.Gold SetCursorPos(touchPoint.X, touchPoint.Y) apimouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0) End If Next End Sub
inkCanvas1_MouseDownメソッドの処理
次にinkCanvas1の上でマウスが押下された時の処理です。
一度inkCanvas1の内容をクリアしておきます。
inkCanvas1の編集モードがInkCanvasEdithingMode.Noneの時の処理です。
新しいRectangleクラスのインスタンスrectを作成します。Point型メンバー変数pにinkCanvas1に対する相対的なマウスポインターの位置をe.GetPosition(inkCanvas1)で格納します。
RectオブジェクトのSetValueメソッドでInkCanvasのLeftPropertyとTopPropertyにinkCanvas1に対するXとY座標を指定します。RectオブジェクトのWidthとHeightを設定します。rectオブジェクトのStrokeDashArray(破線パターンを設定するプロパティ)プロパティに変数doubles(2,2)の値を指定して、破線とします。StrokeThickness(アウトラインの幅)には3を指定します。アウトラインの色にはGoldを指定し、FillにはTransparent(透明色)を指定します。inkCanvas1にrectオブジェクトを追加します。
画像の上でタッチするとGoldの破線枠が表示されます。具体的なコードはリスト11になります。
リスト11 inkCanvas1_MouseDownメソッドの処理
Private Sub inkCanvas1_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles inkCanvas1.MouseDown messageTextBlock.Text = String.Empty inkCanvas1.Children.Clear() Button1.IsEnabled = True If inkCanvas1.EditingMode = InkCanvasEditingMode.None Then rect = New Rectangle p = e.GetPosition(inkCanvas1) rect.SetValue(InkCanvas.LeftProperty, p.X) rect.SetValue(InkCanvas.TopProperty, p.Y) rect.Width = p.X rect.Height = p.Y Dim doubles As New DoubleCollection doubles.Add(2) doubles.Add(2) rect.StrokeDashArray = doubles ' StrokeDashArray(2,2)と同じ rect.StrokeThickness = 3 rect.Stroke = New SolidColorBrush(Colors.Gold) rect.Fill = New SolidColorBrush(Colors.Transparent) inkCanvas1.Children.Add(rect) End If End Sub
inkCanvas1_MouseMoveメソッドの処理
inkCanvas1上でマウスカーソルを移動させた時の処理です。
Point型変数p2にinkCanvas1に対する相対的なマウスポインターの位置をe.GetPosition(inkCanvas1)で格納します。
選択した移動距離の範囲を変数wとhに格納します。移動距離のwの値が0.1と同じか少なかった場合は、rectオブジェクトのSetValueメソッドでInkCanvas.LeftPropertyに移動した範囲のXの値を指定します。rectのWidthに移動した距離を指定します。
移動した距離のhの値が0.1かそれより少なかった場合は、rectオブジェクトのSetValueメソッドでInkCanvas.TopPropertyに移動した範囲のYの値を指定します。rectのHeightに移動した距離を指定します。
具体的なコードはリスト12になります。
リスト12 inkCanvas1_MouseMoveメソッドの処理
Private Sub inkCanvas1_MouseMove(sender As Object, e As MouseEventArgs) Handles inkCanvas1.MouseMove If rect Is Nothing = False Then Dim p2 As Point = e.GetPosition(inkCanvas1) Dim w As Double = p2.X - p.X ' X座標の移動した距離 Dim h As Double = p2.Y - p.Y ' Y座標の移動した距離 If (w <= 0.1) Then rect.SetValue(InkCanvas.LeftProperty, p2.X) rect.Width = p.X - p2.X Else rect.Width = w End If If (h <= 0.1) Then rect.SetValue(InkCanvas.TopProperty, p2.Y) rect.Height = p.Y - p2.Y Else rect.Height = h End If Else Exit Sub End If End Sub
[切り取る(Button1)]がクリックされた時の処理(Button1_Clickメソッド)
File.OpenReadメソッドで、ソリューション・エクスプローラー内のImageフォルダ内の画像を読み取り、streamで参照します。
BitmapImageの新しいインスタンスbmpオブジェクトを作成します。BeginInitでBitmapImageの初期化を開始します。BitmapImageのストリームソースにstreamを指定します。EndInitで初期化を終了します。
bmpオブジェクトで初期化された新しいWriteableBitmapのインスタンスmyWriteableBitmapオブジェクトを作成します。BitmapFactory.ConvertToPbgra32Format(bmp)でbmpをPbgra32フォーマットに変換します。
この変換を行っていないとエラーが表示されますので、注意してください。
WriteableBitmapExのCropメソッドで、選択した範囲を切り取ります。切り取った画像をresultImageに表示します。[保存]ボタンの使用を可能にします。
具体的なコードはリスト13になります。
リスト13 Button1_Clickメソッド処理
Private Sub Button1_Click(sender As Object, e As RoutedEventArgs) Handles Button1.Click Using stream = File.OpenRead("Image/冬の桜.jpg") Dim bmp As BitmapImage = New BitmapImage bmp.BeginInit() bmp.StreamSource = stream bmp.EndInit() Dim myWriteableBitmap = New WriteableBitmap(bmp) myWriteableBitmap = BitmapFactory.ConvertToPbgra32Format(bmp) Dim myCrop = myWriteableBitmap.Crop(rect.GetValue(InkCanvas.LeftProperty), rect.GetValue(InkCanvas.TopProperty), rect.Width, rect.Height) ' 選択した範囲をCropメソッドで切り取る resultImage.Source = Nothing resultImage.Source = myCrop ' 切り取った画像を表示する End Using saveButton.IsEnabled = True End Sub
inkCanvas1_MouseUpメソッドの処理
ReleaseAllTouchCapturesメソッドで、キャプチャされている全てのタッチデバイスをこの要素から解放します。
コードはリスト14になります。
リスト14 inkCanvas1_MouseUpメソッドの処理
Private Sub inkCanvas1_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles inkCanvas1.MouseUp inkCanvas1.ReleaseAllTouchCaptures() End Sub
[保存(saveButton)]がクリックされた時の処理(saveButton_Clickメソッド)
切り出された画像の表示されている、resultImage.Sourceで初期化された、新しいWriteableBitmapのオブジェクトbmpを作成します。PngBitmapEncoderでPNG形式のイメージのエンコードに使用される新しいエンコーダーのインスタンス、myEncoderを作成します。
指定したBitmapSourceから新しいBitmapFrameを作成して、myEncoderに追加します。
File.Opneメソッドで保存するフォルダとファイル名(TrimmingTest.png)を連結して、フォルダにファイルを書きこみ、FileStream変数fsで参照します。
myEncoder.Save(fs)でビットマップイメージを指定したStream(fs)にエンコードします。
保存した旨のメッセージを表示し、[切り取る]と[保存]ボタンの使用を不可とします。
具体的なコードはリスト15になります。
リスト15 saveButton_Clickメソッド
Private Sub saveButton_Click(sender As Object, e As RoutedEventArgs) Handles saveButton.Click Dim bmp As New WriteableBitmap(resultImage.Source) Dim myEncoder = New PngBitmapEncoder myEncoder.Frames.Add(BitmapFrame.Create(bmp)) Using fs As FileStream = File.Open(System.IO.Path.Combine(savePath, "TrimmingTest.png"), FileMode.Create) myEncoder.Save(fs) ' 指定したフォルダにTrimmingTest.pngとして保存する End Using messageTextBlock.Text = savePath & "フォルダにTrimmingTest.pngとして保存しました。" Button1.IsEnabled = False saveButton.IsEnabled = False End Sub
※注意
今回紹介したサンプルコードを動かす際には、「LeapCSharp.NET4.0.dll」や「LeapCSharp.dll」、「Leap.dll」を読者の皆さん自身のフォルダ内にあるDLLファイルに指定し直さなければ動かない可能性があるので、動かない場合は再指定して下さい。
Leap Motionで画像のトリミングと保存を行うためのサンプルプログラム
『新世代モーションコントローラー Leap Motion -Visual Basicによる実践プログラミング-』 第4回のサンプルプログラムです。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- マウス・カーソルで指定した画像の一部を拡大表示するLeap Motionプログラム
- Leap Motionのスクリーン・タップを使った音声の再生と画像の表示
- 画面上の図形を5本の指で操作する基本的なLeap Motionプログラムを作る
- 画面に並んだ写真が指の動きに反応して回転するLeap Motionプログラムを作る
- 写真を突っついて一覧から削除、並び替えするLeap Motionプログラムを作る
- 選択した画像を指の動きに合わせて回転させるLeap Motionプログラムを作る
- 張子の虎をキー・タップすると頭が上下に動くLeap Motionプログラムを作る
- 好きな写真を指で選んで順番に拡大表示するLeap Motionプログラムを作る
- 手の動きに合わせて画面上のキャラクターを操作するLeap Motionプログラムを作る
- Leap MotionアプリをWindowsストアに申請して認定させる