Kinect v2を使って、机の上のリンゴをつかんで移動してみる
2015年1月20日(火)

新しいボディフレームの準備ができているときに発生するイベント処理
リスト4:MainWindow.xaml.vbの一部、リスト3の続き
01 | Private Sub myBodyFrameReader_FrameArrived(sender As Object, e As BodyFrameArrivedEventArgs) |
02 | Using myBodyFrame = e.FrameReference.AcquireFrame (1) |
03 | If myBodyFrame Is Nothing = True Then |
04 | Return |
05 | End If |
06 | myBodyFrame.GetAndRefreshBodyData(myBodies) (2) |
07 | End Using |
08 | CanvasBody.Children.Clear() (3) |
09 | For Each body In myBodies |
10 | For Each joint In body.Joints (4) |
11 | If joint.Value.TrackingState = TrackingState.Tracked Then |
12 | DrawEllipse(joint.Value, 10, Brushes.Transparent) (5) |
13 | If joint.Value.JointType = JointType.HandRight Then |
14 | If body.Joints(JointType.HandTipRight).TrackingState = TrackingState.Tracked Then |
15 | myColorSpacePoint = myKinect.CoordinateMapper.MapCameraPointToColorSpace(body.Joints(JointType.HandTipRight).Position) (6) |
16 | myHandPositionX = CInt(myColorSpacePoint.X * 0.5) (7) |
17 | myHandPositionY = CInt(myColorSpacePoint.Y * 0.5) |
18 | DrawHandState(body.Joints(JointType.HandRight), body.HandRightState, body.HandRightConfidence) (8) |
19 | End If |
20 | End If |
21 | End If |
22 | Next |
23 | Next |
24 | End Sub |
- e.FrameReference.AcquireFrameメソッドで、ボディフレームを取得し、myBodyFrameで参照します。myBodyFrameに何もなかった場合は、何も行いません。
- GetAndRefreshBodyDataメソッドで、更新されたボディデータを取得します。
- CanvasBody内を一度クリアしておきます。
- ボディデータの中を、反復処理を行いながら、繰り返し変数jointで関節の位置を反復処理しながら、関節位置を取得していきます。
- 関節が追跡されている場合は、関節の位置と、関節の位置を描く円の大きさ描く色(透明)を指定して、DrawEllipseを実行します。
- 右手が追跡されている場合は、CoordinateMapper.MapCameraPointToColorSpaceメソッドで、関節の位置を、カメラ空間から距離空間へのポイントにマップし、変数myColorSpacePointで参照します。
- 手のXとY軸の位置を取得して、メンバー変数、myHandPositionXとmyHandPositionYに格納します。
- 右手の位置、状態、そして追跡の精度を引数にして、DrawHandStateを実行します。
カラーフレーム到着時のイベント
リスト5:MainWindow.xaml.vbの一部、リスト4の続き
01 | Private Sub myColorFrameReader_FrameArrived(sender As Object, e As ColorFrameArrivedEventArgs) |
02 | Dim colorFramePorcessed As Boolean = False |
03 | Using myColorFrame As ColorFrame = e.FrameReference.AcquireFrame (1) |
04 | If myColorFrame Is Nothing = False Then (2) |
05 | Dim myColorFrameDescription As FrameDescription = myColorFrame.FrameDescription (3) |
06 | If myColorFrameDescription.Width = colorBitmap.PixelWidth AndAlso myColorFrameDescription.Height = colorBitmap.PixelHeight Then (4) |
07 | If myColorFrame.RawColorImageFormat = ColorImageFormat.Bgra Then |
08 | myColorFrame.CopyRawFrameDataToArray(ColorImagePixelData) (5) |
09 | Else |
10 | myColorFrame.CopyConvertedFrameDataToArray(ColorImagePixelData, ColorImageFormat.Bgra) (6) |
11 | End If |
12 | colorFramePorcessed = True (7) |
13 | End If |
14 | End If |
15 | End Using |
16 | If colorFramePorcessed = True Then |
17 | colorBitmap.WritePixels(New Int32Rect(0, 0, colorBitmap.PixelWidth, colorBitmap.PixelHeight), ColorImagePixelData, colorBitmap.PixelWidth * BytesPerPixel, 0) (8) |
18 | roomImage.Source = colorBitmap (9) |
19 | End If |
20 | End Sub |
- e.FrameReference.AcquireFrameメソッドでカラーフレームを取得し、myColorFrameで参照します。
- myColorFrameにデータがあった場合の処理です。
- KinectSensor から、イメージフレームのプロパティを取得し、変数myColorFrameDescriptionで参照します。
- 取得したプロパティのWidthとHeightが、それぞれcolorBitmapのPixelWidth、PixelHeightと同じであった場合の処理を行います。
- カラー フレーム データの形式がBgraであった場合は、CopyRawFrameDataToArrayメソッドで、Raw フレームのデータ指定された配列(ColorImagePixelData)にコピーします。
- そうでない場合は、CopyConvertedFrameDataToArrayメソッドで、フレームからBGRA形式のバイト列に変換し、バイト配列に格納します。
- Boolean型で宣言していた変数colorFrameProcessedをTrueで初期化します。
- colorFrameProcessed変数がTrueであった場合は、
colorBitmap(WriteableBitmapクラス)のWritePixelsメソッドで、ビットマップの指定した領域内のピクセルを更新します。CopyConvertedFrameDataToArrayメソッドとWritePixelsメソッドの書式については、第3回目を参照してください。9.roomImageのSourceプロパティにcolorBitmapオブジェクトを指定します。これでRGBカメラからの画像が表示されます。
関節の位置に透明の円を表示する処理
リスト6:MainWindow.xaml.vbの一部、リスト5の続き
01 | Private Sub DrawEllipse(myJoint As Joint, R As Integer, myBrush As Brush) |
02 | Dim myEllipse = New Ellipse |
03 | With myEllipse |
04 | .Width = R |
05 | .Height = R |
06 | .Fill = myBrush |
07 | End With |
08 |
09 | point = myKinect.CoordinateMapper.MapCameraPointToDepthSpace(myJoint.Position) (1) |
10 | If point.X < 0 OrElse point.Y < 0 Then |
11 | Return |
12 | End If |
13 | Canvas.SetLeft(myEllipse, point.X - (R / 2)) (2) |
14 | Canvas.SetTop(myEllipse, point.Y - (R / 2)) |
15 | If myJoint.JointType = JointType.HandRight Then |
16 | commonJoint.JointType = JointType.HandRight |
17 | If flag = True Then |
18 | myImage.Margin = New Thickness(point.X, point.Y, 0, 0) (3) |
19 | End If |
20 | '.Margin = New Thickness(point.X, point.Y, 0, 0) |
21 | End If |
22 | CanvasBody.Children.Add(myEllipse) |
23 | End Sub |
直径10ピクセルで透明の円を作成します。直径はDrawEllipseを呼ぶ際に指定しています(リスト4)。
- CoordinateMapper.MapCameraPointToDepthSpaceメソッドで、関節の位置を、カメラ空間から距離空間へのポイントにマップし、メンバー変数pointで参照します。
- SetLeftとSetTopメソッドで透明な円を、指定したXとY軸に描きます。
- 関節のタイプが右手であり、変数flagがTrue、つまり手の形がグーの場合は、myImageオブジェクトをPoint.XとPoint.Yの位置に移動します。これにより、リンゴをつかんで移動します。変数flagの初期化は、後述のDrawHandState(リスト7)の中で行っています。プレイヤーには透明な円で関節の位置が表示されていますが、目には見えません。
プレイヤーの手の形によって条件分岐を行う処理
リスト7:MainWindow.xaml.vbの一部、リスト6の続き
01 | Private Sub DrawHandState(joint As Joint, state As HandState, myTrackingConfidence As TrackingConfidence) |
02 | If myTrackingConfidence <> TrackingConfidence.High Then |
03 | Return |
04 | End If |
05 |
06 | If state = HandState.Open Then (1) |
07 | flag = False |
08 | ElseIf state = HandState.Closed Then (2) |
09 | appleCanvas.Children.Clear() |
10 | Image1.Source = Nothing |
11 | myImage.Margin = New Thickness(point.X, point.Y, 0, 0) |
12 | appleCanvas.Children.Add(myImage) |
13 | flag = True (3) |
14 | End If |
15 | End Sub |
- 手がパーの状態なら、flagにFalseを代入します。
- 手がグーの状態の場合は、リンゴが表示されていた領域をクリアし、新しく移動された位置にリンゴを表示します。
- flagにTrueを代入します。
ウインドウが閉じられる場合の処理
リスト8:MainWindow.xaml.vbの一部、リスト7の続き
1 | Private Sub MainWindow_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing |
2 | If myKinect Is Nothing = False Then |
3 | myKinect.Close() |
4 | myKinect = Nothing |
5 | End If |
6 | End Sub |
7 | End Class |
Kinectが動作している場合は、Kinectを閉じ、全ての関連付けから解放します。
実際にプログラムを動作させると下記の動画のようになります。リンゴをつかんで動かしている感じがお分かりいただけると思います。
連載バックナンバー
Think ITメルマガ会員登録受付中
Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。
全文検索エンジンによるおすすめ記事
- Kinect v2で実現する打楽器のバーチャル演奏
- Kinect v2の音声認識で「仮面」を選んで変身してみる
- Kinect v2のジェスチャーでBing Mapsを未来的に直感操作する
- Kinect v2を使った「じゃんけんゲーム」を作る
- Kinect v2のカメラから画像を取り込んで表示する基本プログラム
- Kinectで手の動きとカーソルを連動して操作するサンプル
- Kinectで人体を認識して棒人間を動かすサンプル
- Kinectで手の動きに合わせてモニタ上の画像を動かすサンプル
- Kinect v2のIRセンサーから赤外線画像を読み込む
- Kinect v2の深度センサーから取り込んだ画像を表示する