Kinectで手の動きとカーソルを連動して操作するサンプル

2012年7月30日(月)
薬師寺 国安

前ページからの続きです。

スケルトンのフレーム更新を行い、手の動きでマウスカーソルを操作する処理

e.OpenSkeletonFrameメソッドで、新しいフレームのスケルトン情報を取得します。このメソッドで取得するskeletonFrameは、Usingで括るか、明示的にDisposeする必要があります。
SkeletonFrameクラスは、フレームごとのスケルトンデータを表すクラスです。

スケルトンの配列の長さ分(skeletonFrameData.SkeletonArrayLength - 1)のSkeletonクラス型の配列変数skeletonArrayを宣言します。Skeletonクラスはプレイヤーごとのスケルトン情報を表すクラスです。
CopySkeletonDataToメソッドは、現在の SkeletonFrameにある、スケルトンのデータを指定した配列にコピーします。
これで取得されるデータはプレイヤー分取得されますので、各プレイヤーのトラッキング状態を確認します。

プレイヤーごとのスケルトン情報をもつ、skeletonArray配列変数内を、繰り返し変数skeletonDataで反復処理しながら以下の処理を繰り返します。

SkeletonTrackingState.Trackedで全ての関節の位置がトラッキングされ、左手や右手がトラッキングされている場合は、スケルトンの座標データ持つJointクラス型のjointRightとjointLeft変数を宣言し、Jointsプロパティで右手と左手の関節部分を取得します。

同様にJointクラス型のscaleRightとscaleLeft変数を宣言します。
ScaleToメソッドに、プライマリ ディスプレイ モニターの画面の幅(ピクセル単位)を示す値と、プライマリ ディスプレイ モニターの画面の高さ(ピクセル単位)を示す値を指定します。
また、定数メンバ変数として宣言しておいたSkeletonMaxXとSkeletonMaxYの値も指定して、指定した最大幅と最大高さに、Jointオブジェクトの位置をスケーリングします。

ScaleToメソッドの書式は下記の通りです。このScaleToメソッドはCoding4Fun.Kinect.Toolkitに含まれるメソッドです。

Joint.ScaleTo(width As Integer, height As Integer, maxSkeletonX As Float, maxSkeletonY As Float)

Fix関数は小数部分を取り除いた整数値を返す関数です。スケーリングされた値は、それぞれscaleRightとscaleLeft変数に格納しておきます。

変数cursorXに右手のX座標の位置を、cursorYには右手のY座標の位置を格納します。

右手のY座標の位置が33cmより大きく、または左手のY座標の位置が33cmより大きくなければ(つまり、左手が下におろされている場合)は、ブール型変数leftClickの値をTrue(ホールドされた状態)にし、そうでない場合は(左手が上に挙げられている場合)False(ホールドが解除)で初期化します。

SendMouseInputメソッドで、右手の動きに合わせてカーソルを制御し、左手の上げ下げで現在のカーソル位置でのホールドと解除を実現します。SendMouseInputはCursorClass.dllに含まれています。書式は下記の通りです。

SendMouseInput(ByVal positionX As Integer, ByVal positionY As Integer, ByVal maxX As Integer, ByVal maxY As Integer, ByVal leftDown As Boolean)

positionXには右手のX座標の位置、positionYには右手のY座標の位置、maxXにはプライマリ ディスプレイ モニターの画面の幅(ピクセル単位)を示す値、maxYにはプライマリ ディスプレイ モニターの画面の高さ(ピクセル単位)を示す値、leftDownには左手の動きによって判別されるブール型変数leftClickの値を指定します。

  Private Sub SensorSkeletonReady(e As AllFramesReadyEventArgs)
    Using skeletonFrameData As SkeletonFrame = e.OpenSkeletonFrame
    If skeletonFrameData Is Nothing = True Then
      Return
    End If
    Dim skeletonArray(skeletonFrameData.SkeletonArrayLength - 1) As Skeleton
  
    skeletonFrameData.CopySkeletonDataTo(skeletonArray)
 
    For Each skeletonData In skeletonArray
      If skeletonData.TrackingState = SkeletonTrackingState.Tracked Then
        If skeletonData.Joints(JointType.HandLeft).TrackingState = JointTrackingState.Tracked AndAlso skeletonData.Joints(JointType.HandRight).TrackingState = JointTrackingState.Tracked Then
            Dim cursorX As Integer
            Dim cursorY As Integer
            Dim jointRight As Joint = skeletonData.Joints(JointType.HandRight)
            Dim jointLeft As Joint = skeletonData.Joints(JointType.HandLeft)
            Dim scaledRight As Joint = jointRight.ScaleTo(CInt(Fix(SystemParameters.PrimaryScreenWidth)), CInt(Fix(SystemParameters.PrimaryScreenHeight)), SkeletonMaxX, SkeletonMaxY)
            Dim scaledLeft As Joint = jointLeft.ScaleTo(CInt(Fix(SystemParameters.PrimaryScreenWidth)), CInt(Fix(SystemParameters.PrimaryScreenHeight)), SkeletonMaxX, SkeletonMaxY)
 
            cursorX = CInt(Fix(scaledRight.Position.X))
            cursorY = CInt(Fix(scaledRight.Position.Y))
 
            Dim leftClick As Boolean
            If jointRight.Position.Y > ClickThreshold OrElse (Not jointLeft.Position.Y > ClickThreshold) Then
              leftClick = True
            Else
              leftClick = False
            End If
  
    KinectCursor.SendMouseInput(cursorX, cursorY, CInt(Fix(SystemParameters.PrimaryScreenWidth)), CInt(Fix(SystemParameters.PrimaryScreenHeight)), leftClick)
            Return
          End If
        End If
      Next
    End Using
  End Sub

RGBカメラを有効にしてカメラの画像を表示する

Image1という名前を持つImageコントロールのSourceプロパティに、e.OpenColorImageFrameメソッドで、新しいフレームのRGBカメラ情報を取得し、Coding4Fun.Kinect.Wpfの拡張メソッドであるToBitmapSourceで、colorFrameをBitmapSourceに変換して指定します。

このメソッドで取得するColorImageFrameは、Usingで括るか、明示的にDisposeする必要があります。

  Private Sub SensorColorFrameReady(e As AllFramesReadyEventArgs)
      Using colorFrame As ColorImageFrame = e.OpenColorImageFrame
        If colorFrame Is Nothing = True Then
          Return
        End If
      Image1.Source = colorFrame.ToBitmapSource
    End Using
  End Sub

Kinect センサーの動作を停止する処理

Kinectセンサーが動作している場合は、動作を停止し、リソースを解放します。

  Private Sub StopKinect(ByVal sensor As KinectSensor)
    If sensor Is Nothing = False Then
      If sensor.IsRunning = True Then
        sensor.Stop()
        sensor.Dispose()
      End If
    End If
  End Sub

ウィンドウが閉じられた時の処理

動作しているKinectセンサーを引数に、Kinectセンサーの動作を停止する、StopKinectプロシージャを実行します。

  Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing  
    StopKinect(newSensor)
  End Sub
End Class

今回のサンプルは以上で終了です。右手と左手を使った操作に慣れるのが少し難しいですが、未来的なインターフェイスを体験できるかと思います。

それでは、次回もお楽しみに。

  • Kinectで手の動きに合わせてカーソルを動かすサンプル

薬師寺国安事務所

薬師寺国安事務所代表。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 Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

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

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