Kinectで人体を認識して棒人間を動かすサンプル

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

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

骨格と接合部分を描画する

DrawBoneメソッドで、「胴体」「左腕」「右腕」「左脚」「右脚」を描いていきます。

接合部分をJoint型の繰り返し変数myJointで反復処理しながら、以下の処理を行います。

接合部分が追跡されている場合は、Brushクラス型の変数drawBrushにメンバ変数[追跡された関節のブラシ]のブラシを指定します。

接合部分が推測されている場合は、メンバ変数推測された関節のブラシ(黄色)を指定します。DrawingContext.DrawEllipse メソッドで、指定した Brush および Pen を使用して楕円を描画します。書式は下記の通りです。

DrawingContext.DrawEllipse(楕円の塗りつぶしに使用するブラシ[これは省略可能であり、Nothing を指定できます], 楕円のストロークを描画する際に使用するペン[これは省略可能であり、Nothing を指定できます], 楕円の中心の位置, 楕円の横半径, 楕円の縦半径)

「楕円の塗りつぶしに使用するブラシ」には変数のdrawBrushの値を指定します。「楕円のストロークを描画する際に使用するペン」にはNothingを指定し、「楕円の中心の位置」には、スケルトンポイントを出力する、SkeletonPointToScreen関数の戻り値を指定します。

「楕円の横半径」と「楕円の縦半径」にはメンバ定数変数[関節の太さ]の3を指定します。

01Private Sub DrawBonesAndJoints(ByVal skeleton As Skeleton, ByVal drawingContext As DrawingContext)
02    
03  ‘胴体
04  DrawBone(skeleton, drawingContext, JointType.Head, JointType.ShoulderCenter)
05  DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderLeft)
06  DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, s)
07  DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.Spine)
08  DrawBone(skeleton, drawingContext, JointType.Spine, JointType.HipCenter)
09  DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipLeft)
10  DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipRight)
11 
12  '左腕
13  DrawBone(skeleton, drawingContext, JointType.ShoulderLeft, JointType.ElbowLeft)
14  DrawBone(skeleton, drawingContext, JointType.ElbowLeft, JointType.WristLeft)
15  DrawBone(skeleton, drawingContext, JointType.WristLeft, JointType.HandLeft)
16 
17  ' 右腕
18  DrawBone(skeleton, drawingContext, JointType.ShoulderRight, JointType.ElbowRight)
19  DrawBone(skeleton, drawingContext, JointType.ElbowRight, JointType.WristRight)
20  DrawBone(skeleton, drawingContext, JointType.WristRight, JointType.HandRight)
21  
22  '左脚
23  DrawBone(skeleton, drawingContext, JointType.HipLeft, JointType.KneeLeft)
24  DrawBone(skeleton, drawingContext, JointType.KneeLeft, JointType.AnkleLeft)
25  DrawBone(skeleton, drawingContext, JointType.AnkleLeft, JointType.FootLeft)
26 
27  ' 右脚
28  DrawBone(skeleton, drawingContext, JointType.HipRight, JointType.KneeRight)
29  DrawBone(skeleton, drawingContext, JointType.KneeRight, JointType.AnkleRight)
30  DrawBone(skeleton, drawingContext, JointType.AnkleRight, JointType.FootRight)
31 
32  For Each myJoint As Joint In skeleton.Joints
33    Dim drawBrush As Brush = Nothing
34 
35    If myJoint.TrackingState = JointTrackingState.Tracked Then
36      drawBrush = 追跡された関節のブラシ
37    ElseIf  myJoint.TrackingState = JointTrackingState.Inferred Then
38      drawBrush = 推測された関節のブラシ
39    End If
40 
41    If drawBrush Is Nothing = False Then
42      drawingContext.DrawEllipse(drawBrush, Nothing, SkeletonPointToScreen(myJoint.Position), 関節の太さ, 関節の太さ)
43    End If
44  Next
45End Sub

スケルトンポイントを出力する関数

距離カメラのX-Y座標データを表す、DepthImagePoint構造体の変数depthPointを宣言し、MapSkeletonPointToDepthメソッドで、スケルトンの座標を、距離カメラの座標に変換します。距離カメラの解像度は640×480で、1秒当たり30フレームとなります。

レンダー領域を制限し、距離カメラのxとy座標を戻り値とします。

01Private Function SkeletonPointToScreen(ByVal skelpoint As SkeletonPoint) As Point
02  Dim depthPoint As DepthImagePoint = newSensor.MapSkeletonPointToDepth(skelpoint, DepthImageFormat.Resolution640x480Fps30)
03  Dim x As Double = depthPoint.X
04  If x > ScreenWidth Then
05    x = ScreenWidth
06  ElseIf x < 0 Then
07    x = 0
08  End If
09 
10  Dim y As Double = depthPoint.Y
11  If y > ScreenHeight Then
12    y = ScreenHeight
13  ElseIf y < 0 Then
14    y = 0
15  End If
16  Return New Point(x, y)
17End Function

骨格と接合部分を描画するメソッド

スケルトンの部位を特定する、Joint型の変数myJoint0を宣言します。同様にmyJoint1変数を宣言します。これらの関節のいずれかを見つけることができない場合は、終了します。両方のポイントが推論される場合は描画しません。

Penクラス型の変数drawPenを宣言し、メンバ変数[推測された骨のペン色と幅](Navyで幅10)で初期化しておきます。

両方の接合部位が追跡されている場合は、変数drawPenにメンバ変数[追跡された骨のペン色と幅](赤で幅6)で初期化します。

DrawingContext.DrawLine メソッドで、指定したPenを使用して、指定した Points の間の線を描画します。書式は下記の通りです。

DrawingContext.DrawLine(線のストロークを描画する際に使用するペン, 線の開始点, 線の終点)

「線のストロークを描画する際に使用するペン」にはPen型の変数drawPenを指定します。「線の開始点」と「線の終点」には、スケルトンポイントを出力する関数SkeletonPointToScreenに、引数として、それぞれの関節の位置を渡して取得できる、戻り値を指定します。

01Private Sub DrawBone(ByVal skeleton As Skeleton, ByVal drawingContext As DrawingContext, ByVal jointType0 As JointType, ByVal jointType1 As JointType)
02  Dim myJoint0 As Joint = skeleton.Joints(jointType0)
03  Dim myJoint1 As Joint = skeleton.Joints(jointType1)
04 
05  If myJoint0.TrackingState = JointTrackingState.NotTracked OrElse myJoint1.TrackingState = JointTrackingState.NotTracked Then
06    Return
07  End If
08  If myJoint0.TrackingState = JointTrackingState.Inferred AndAlso myJoint1.TrackingState = JointTrackingState.Inferred Then
09    Return
10  End If
11 
12  Dim drawPen As Pen = 推測された骨のペン色と幅
13  If myJoint0.TrackingState = JointTrackingState.Tracked AndAlso myJoint1.TrackingState = JointTrackingState.Tracked Then
14    drawPen = 追跡された骨のペン色と幅
15  End If
16   
17  drawingContext.DrawLine(drawPen, SkeletonPointToScreen(myJoint0.Position), SkeletonPointToScreen(myJoint1.Position))
18End Sub

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

Kinectセンサーが動作している場合は、イベントとイベント ハンドラの関連付けを解除します。Kinectセンサーの動作を停止し、リソースを解放します。

01  Private Sub StopKinect(sensor As KinectSensor)
02    If sensor Is Nothing = False Then
03      If sensor.IsRunning = True Then
04        RemoveHandler sensor.SkeletonFrameReady, AddressOf SkeletonsReady
05        sensor.Stop()
06        sensor.Dispose()
07      End If
08    End If
09  End Sub
10End Class

今回のサンプルは以上で終了です。このサンプルを応用すれば、自分の動きにあわせてXboxのゲームのようにアバターが動くアプリが作れるかもしれませんね。棒人間が動くだけでも十分楽しいので、ぜひチャレンジしてみてください。

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

  • Kinectで人間の身体に対応したスケルトンジョイントを取得するサンプル

  • スケルトン ジョイントをRGB画像データに重ねて表示するサンプル

  • 人間の動きに合わせて棒人間を動かすサンプル

薬師寺国安事務所

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

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