PR

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

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

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