PR

画面上の図形を5本の指で操作する基本的なLeap Motionプログラムを作る

2013年10月10日(木)
薬師寺 国安

プログラム・コードはリスト4のようになります。

リスト4(UpDownModel.vb) 指のアップ・ダウンで円を拡大縮小するクラス

Imports System.ComponentModel
Imports Leap
Public Class UpDownModel

'  プロパティの値が変更されたことをクライアントに通知する、
'  INotifyPropertyChangedインターフェースをインプリメントしておく。
  Implements INotifyPropertyChanged
 
  Private ctlr As Controller
  Private listener As LeapListener
  
'  Newメソッド
'  各インスタンスを作成して、AddHandlerステートメントで、listenerオブジェクトの
'  LeapSwipeイベントに、SwipeActionベントハンドラ—を追加する。 
  Public Sub New()
    ctlr = New Controller
    listener = New LeapListener
    ctlr.AddListener(listener)
    AddHandler listener.LeapSwipe, AddressOf Me.SwipeAction
  End Sub

‘ EllipseHeightプロパティの定義
  Private myHeight As Double
 
  Public Property EllipseHeight As Double
    Get
      Return myHeight
    End Get
    Set(value As Double)
      myHeight = value
      OnPropertyChanged("EllipseHeight")
    End Set
  End Property

'  EllipseWidthプロパティの定義
  Private myWidth As Double
  Public Property EllipseWidth As Double
    Get
      Return myWidth
    End Get
    Set(value As Double)
      myWidth = value
      OnPropertyChanged("EllipseWidth")
    End Set
  End Property

'  UpとDownによってEllipseHeightとEllipseWidthの値を変化させるSwipeActionメソッドの処理
  Private Sub SwipeAction(ByVal sd As SwipeDirection)
    Select Case sd
      Case SwipeDirection.Up
        EllipseHeight += 10
        EllipseWidth += 10
 
        Exit Select
      Case SwipeDirection.Down
 
        EllipseHeight -= 10
        EllipseWidth -= 10
        Exit Select
    End Select
  End Sub

' プロパティの値が変更された時に、変更されたことをクライアントに通知する
'  PropertyChangedイベント。
  Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

'  OnPropertyChangedメソッドの処理
'  RaseEventでプロパティ名で初期化されたPropertyChangedイベントを発生させる。
  Private Sub OnPropertyChanged(ByVal propertyName As String)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
  End Sub
End Class

MainWindow.xaml内に[UpDownModel]を取り込む。

まず名前空間として「xmlns:local="clr-namespace:FingerRecognizeUpDown"」を定義します。

次にプロパティ要素内に「」と記述します。MainWindow.xaml内に「UpDownModel」クラスが取り込まれます。リスト5のコードのようになります。

※注意
プロパティ要素内に「」と記述すると、「」の下に波線が表示され、マウスカーソルを持っていくと、「指定されたファイルが見つかりません。」のエラーが表示されますが、実行には問題はないので、無視しても構いません。

リスト5(MainWindow.xaml) 「UpDownMode」を取り込んだMainWindow.xaml

<Window x:Class="MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" 
  xmlns:local="clr-namespace:FingerRecognizeUpDown"
  Title="MainWindow" Height="768" Width="1366" >
  <Window.DataContext>
    <local:UpDownModel/>
  </Window.DataContext>
 ・・・・以下コード略・・・・
</Window>

プログラム・コード(MainWindow.xaml.vb)指の個数を表示させる処理

MainWindows.xaml.vbファイルを見ていきましょう(リスト6)。

新しいControllerクラスのインスタンスであるleapメンバー変数を宣言します。次に、インク・ストローク(=System.Windows.Ink名前空間のStrokeクラスで表現される、WPF上でのインクの線)の外観を指定する新しいDrawingAttributesクラス(System.Windows.Ink名前空間)のインスタンスである「touchIndicatorメンバー変数」を宣言します。

MainWindow_Loadedメソッドの処理

MainWindow_Loadedメソッド(=メイン・ウィンドウのLoadedイベントのハンドラー)では、MainWindowが読み込まれたときの処理を実装します。

AddHandlerステートメントを使って、構成ツリーのオブジェクトがレンダリングされる直前に発生する「CompositionTarget.Renderingイベント」に対するイベント・ハンドラーとしてUpdateメソッドを指定します(※Updateメソッドの実装内容は後述)。

インク・ストロークの外観を表す、DrawingAttributesオブジェクトのインスタンス「touchIndicator」のWidthプロパティとHeightプロパティにそれぞれ「30」を指定します。スタイラスの形状を指定するStylusTipプロパティに「StylusTip.Ellipse」を指定して円形とします。Leap Motionの上で指をかざすと、かざした指の本数が5本で、30px(px=ピクセル)の円が表示されるようになります。

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オブジェクトを使用することで、指やツール(=ペンなど)の位置を実際のディスプレイの座標系に変換できます。詳細な図については、「Leap Motionでのタッチ操作はどう開発するのか?」を参照してください。

Leap.Frame.Pointablesプロパティで得られるPointableListオブジェクト内を変数「Pointable」で反復処理しながら、1つずつPointableオブジェクトを処理し、それぞれのタッチ位置を取得していきます。

interactionBoxオブジェクトのNormalizePointメソッドに引数としてPointable.StabilizedTipPositionプロパティ値を渡し、ポインター上の位置を取得します。

変数「windowWidth」と「windowHeight」で表されたクライアント領域のウィンドウがある場合、

Dim tx As Double = normalizedPosition.x * windowWidth

Dim ty As Double = windowHeight - normalizedPosition.y * windowHeight

のコードで示す計算式を使用してこのウィンドウ内のタッチ・ポイントの2D座標を得ることができます。

最後に、

  Dim tips As New StylusPointCollection(New StylusPoint() {touchPoint})
  Dim touchStroke As New Stroke(tips, touchIndicator)
  paintCanvas.Strokes.Add(touchStroke)

と記述して、ディスプレイ上に円形のタッチ・ポイントを表示します。

実際のコードはリスト6になります。

リスト6(MainWindow.xaml.vb)

Imports Leap
Imports System.Windows.Ink
Class MainWindow
  Private leap As New Controller
  Private windowWidth As Double = 1366
  Private windowHeight As Double = 768
  Private touchIndicator As New DrawingAttributes

'  MainWindow_Loadedメソッドの処理
  Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    AddHandler CompositionTarget.Rendering, AddressOf Update'  Updateメソッドをイベント・ハンドラーに追加する
    touchIndicator.Width = 30
    touchIndicator.Height = 30
    touchIndicator.StylusTip = StylusTip.Ellipse' スタイラスの形状を30pxの円形に指定する
  End Sub

'  Updateメソッドの処理
  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

'  Leap Motionで認識できる可動範囲を取得する
    Dim interactionBox As InteractionBox = leap.Frame.InteractionBox
    For Each Pointable As Pointable In leap.Frame.Pointables
      Dim normalizedPosition As Leap.Vector = interactionBox.NormalizePoint(Pointable.StabilizedTipPosition)
      Dim tx As Double = normalizedPosition.x * windowWidth
      Dim ty As Double = windowHeight - normalizedPosition.y * windowHeight
      Dim touchPoint As StylusPoint = New StylusPoint(tx, ty) '  ウィンドウ内のタッチ・ポイントの位置を取得する
 
      Dim tips As New StylusPointCollection(New StylusPoint() {touchPoint})
      Dim touchStroke As New Stroke(tips, touchIndicator)
      paintCanvas.Strokes.Add(touchStroke) '  ディスプレイ上にタッチ・ポイントを表示
    Next
  End Sub
End Class

これでVS2012のメニューから[デバッグ]−[デバッグ開始]と実行すると、5本の指のアップ・ダウンで円が拡大縮小表示されます。

リスト5を見ていただくとわかりますが、画面のWidthに1366、Heightに768と指定し、全画面表示にはしていません。

※注意
サンプルをダウンロードして動かす場合は、「LeapCSharp.NET4.0.dll」や「LeapCSharp.dll」、「Leap.dll」を読者の方自身のフォルダ内にあるDLLファイルに指定し直さなければ動かない可能性があるので、動かない場合は再指定してください。

Airspace Storeで配布中のアプリを少しだけ紹介

Leap Motionの有料、無料アプリを販売しているAirspace Storeがあります。
筆者は無料のアプリを2つほどダウンロードして試してみました。

まず、「Flocking」は下記の図のように、指の動きに合わせて魚群が移動する美しいアプリです。

Flockingの画面(クリックで拡大)

もう一つは「ESCAPE VELOCITY」というシューティングゲームです。筆者はゲームが苦手なため、全く操作ができませんでした(-_-;)

ESCAPE VELOCITYの画面(クリックで拡大)
Think IT会員限定特典
  • 5本の指でオブジェクトを拡大・縮小させるプログラム

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

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)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think IT会員サービス無料登録受付中

Think ITでは、より付加価値の高いコンテンツを会員サービスとして提供しています。会員登録を済ませてThink ITのWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

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