Kinectで手の動きに合わせてモニタ上の画像を動かすサンプル

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

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

スケルトンの位置を取得する処理

Kinectセンサーの距離カメラから、距離カメラのフレームデータを表すDepthImageFrameクラス型のdepth変数を宣言し、OpenDepthImageFrameメソッドで、距離カメラのフレームデータを取得します。
距離データのピクセル座標、および距離、プレイヤーIDを表す、DepthImagePoint構造体のleftDepthPoint変数を宣言し、MapFromSkeletonPointメソッドで、スケルトンの座標を、距離カメラの座標に変換します。この場合、左手の位置を距離カメラの座標に変換します。同じく右手の位置も距離カメラの座標に変換します。MapFromSkeletonPointメソッドの書式は下記の通りです。

DepthImageFrame. MapFromSkeletonPoint(変換するスケルトン座標)

次に、RGBデータのピクセル座標を表す、ColorImagePoint構造体の変数leftColorPointを宣言し、MapToColorImagePointメソッドで、距離カメラの座標をRGBカメラの座標に変換します。書式は下記の通りです。

DepthFrameImage.MapToColorImagePoint(距離カメラのX座標,距離カメラのY座標,RGBカメラのフォーマット)

この場合、左手の距離カメラのX座標と、Y座標をRGBフォーマット(解像度が640×480、フレーム レートは 毎秒30フレーム)に変換しています。同様に右手に対しても同じ処理を行います。
距離カメラのデータをRGBカメラ(実写)のデータにマップします。
RGBカメラの座標に変換された、左手のデータと右手のデータを引数に、画像が回転するScaleプロシージャを実行します。
Image1とRGBカメラの座標に変換された、左手、右手のデータを引数に、手の動きに合わせて画像の位置が変化するCameraPositionプロシージャを実行します。
左手のY座標が、右手のY座標より15㎝以上大きく、または、右手のY座標の位置が、左手のY座標より15㎝以上大きい場合は、画像を回転するImageRotateプロシージャを実行します。右手と左手、または右手と左手が、上下に15㎝以上離れて重なった場合に画像が回転します。
左手が上の場合はmyFlagはTrue、右手が上の場合はmyFlagはFalseとします。この値で右回転か左回転かを決めています。

    Private Sub GetCameraPoint(ByVal first As Skeleton, ByVal e As AllFramesReadyEventArgs)
      Try
        Using depth As DepthImageFrame = e.OpenDepthImageFrame()
          Dim leftDepthPoint As DepthImagePoint = depth.MapFromSkeletonPoint(first.Joints(JointType.HandLeft).Position)
          Dim rightDepthPoint As DepthImagePoint = depth.MapFromSkeletonPoint(first.Joints(JointType.HandRight).Position)
          Dim leftColorPoint As ColorImagePoint = depth.MapToColorImagePoint(leftDepthPoint.X, leftDepthPoint.Y, ColorImageFormat.RgbResolution640x480Fps30)
          'right hand
          Dim rightColorPoint As ColorImagePoint = depth.MapToColorImagePoint(rightDepthPoint.X, rightDepthPoint.Y, ColorImageFormat.RgbResolution640x480Fps30)
 
          Scale(leftColorPoint, rightColorPoint)
          CameraPosition(Image1, leftColorPoint)
          CameraPosition(Image1, rightColorPoint)
 
          If leftColorPoint.Y > rightColorPoint.Y + 150 OrElse rightColorPoint.Y > leftColorPoint.Y + 150 Then
            If leftColorPoint.Y > rightColorPoint.Y + 150 Then myFlag = True
            If rightColorPoint.Y > leftColorPoint.Y + 150 Then myFlag = False
            ImageRotate()
          End If
        End Using
      Catch
        Exit Sub
      End Try
    End Sub

画像が拡大縮小する処理

myScaleという名前を持つ、ScaleTransformのScaleX(x軸のスケールファクターを設定)とScaleY(y軸のスケールファクターを設定)に、RGBのピクセル座標に変換された左手のX座標の位置から、右手のX座標の位置を差し引いた値に0.01を乗算して指定します。0.01を乗算しないと巨大な画像が表示されますので、必ず0.01乗算する必要があります。

    Private Sub Scale(lcolorPoint As ColorImagePoint, rcolorPoint As ColorImagePoint)
      myScale.ScaleX = (lcolorPoint.X - rcolorPoint.X) * 0.01
      myScale.ScaleY = (lcolorPoint.X - rcolorPoint.X) * 0.01
      myRotate.Angle = 180
    End Sub

画像が回転する処理

myFlagがTrueなら右回転、Falseなら左回転になります。メンバ変数noの値を10ずつ増減させて、Angleの値に指定して回転させます。10度ずつ回転します。画像の中心を軸に回転するよう
myRotate.CenterX = Image1.Width / 2
myRotate.CenterY = Image1.Height / 2
と指定しておきます。

    Private Sub ImageRotate()
      If no >= 360 Then no = 0
      myRotate.Angle = no
      myScale.ScaleX = 1.5
      myScale.ScaleY = 1.5
      myRotate.CenterX = Image1.Width / 2
      myRotate.CenterY = Image1.Height / 2
      If myFlag = True Then
        no = no + 10
      Else
        no = no - 10
      End If
    End Sub

画像が、右手、左手の動きに反応する処理

Coding4Fun Kinect ToolkitのScaleToメソッドで、指定した幅と高さにJointオブジェクトの位置をスケーリングします。書式は下記です。1920×1080は筆者のPCの解像度です。

Joint.ScaleTo(width As Integer, height As Integer)

Canvas.SetLeftとSetTopプロパティの書式は下記です。

Canvas.SetLeft(プロパティ値の書き込み対象の要素,指定した要素のCanvas.Left属性を設定)
Canvas.SetTop(プロパティ値の書き込み対象の要素,指定した要素のCanvas.Top属性を設定)

  Private Sub ScalePosition(ByVal element As FrameworkElement, ByVal joint As Joint)
    Dim scaledJoint As Joint = joint.ScaleTo(1920, 1080)
      Canvas.SetLeft(element, scaledJoint.Position.X)
      Canvas.SetTop(element, scaledJoint.Position.Y)
  End Sub

手の動きに合わせて画像の位置が変化する処理

Canvas.SetLeftとSetTopプロパティの書式は下記です。

Canvas.SetLeft(プロパティ値の書き込み対象の要素,指定した要素のCanvas.Left属性を設定)
Canvas.SetTop(プロパティ値の書き込み対象の要素,指定した要素のCanvas.Top属性を設定)

    Private Sub CameraPosition(ByVal element As FrameworkElement, ByVal point As ColorImagePoint)
      Canvas.SetLeft(element, point.X - (CLng(element.Width) / 2))
      Canvas.SetTop(element, point.Y - CLng(element.Height) / 2)
    End Sub

円が手の動きに合わせて動く処理

    Private Sub SetEllipsePosition(myEllipse As Ellipse, myJoint As Joint)
      Canvas.SetLeft(myEllipse, (320 * myJoint.Position.X) + 320)
      Canvas.SetTop(myEllipse, (240 * -myJoint.Position.Y) + 240)
    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 センサーを停止するStopKinectプロシージャを、動作しているKinect センサーを引数にして実行します。

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

今回のサンプルは以上で終了です。

薬師寺国安事務所

薬師寺国安事務所代表。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メルマガ会員のサービス内容を見る

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