PR

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

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

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

Think IT会員限定特典
  • 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のWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

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

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