新しいボディフレームの準備ができているときに発生するイベント処理

新しいボディフレームの準備ができているときに発生するイベント処理

リスト4:MainWindow.xaml.vbの一部、リスト3の続き

Private Sub myBodyFrameReader_FrameArrived(sender As Object, e As BodyFrameArrivedEventArgs)
    Using myBodyFrame = e.FrameReference.AcquireFrame   (1)
        If myBodyFrame Is Nothing = True Then
            Return
        End If
        myBodyFrame.GetAndRefreshBodyData(myBodies)    (2)
    End Using
    CanvasBody.Children.Clear()   (3)
    For Each body In myBodies
        For Each joint In body.Joints   (4)
            If joint.Value.TrackingState = TrackingState.Tracked Then
                DrawEllipse(joint.Value, 10, Brushes.Transparent)    (5)
                If joint.Value.JointType = JointType.HandRight Then
                    If body.Joints(JointType.HandTipRight).TrackingState = TrackingState.Tracked Then
                        myColorSpacePoint = myKinect.CoordinateMapper.MapCameraPointToColorSpace(body.Joints(JointType.HandTipRight).Position)    (6)
                        myHandPositionX = CInt(myColorSpacePoint.X * 0.5)  (7)
                        myHandPositionY = CInt(myColorSpacePoint.Y * 0.5)
                        DrawHandState(body.Joints(JointType.HandRight), body.HandRightState, body.HandRightConfidence)    (8)
                    End If
                End If
            End If
        Next
    Next
End Sub
  1. e.FrameReference.AcquireFrameメソッドで、ボディフレームを取得し、myBodyFrameで参照します。myBodyFrameに何もなかった場合は、何も行いません。
  2. GetAndRefreshBodyDataメソッドで、更新されたボディデータを取得します。
  3. CanvasBody内を一度クリアしておきます。
  4. ボディデータの中を、反復処理を行いながら、繰り返し変数jointで関節の位置を反復処理しながら、関節位置を取得していきます。
  5. 関節が追跡されている場合は、関節の位置と、関節の位置を描く円の大きさ描く色(透明)を指定して、DrawEllipseを実行します。
  6. 右手が追跡されている場合は、CoordinateMapper.MapCameraPointToColorSpaceメソッドで、関節の位置を、カメラ空間から距離空間へのポイントにマップし、変数myColorSpacePointで参照します。
  7. 手のXとY軸の位置を取得して、メンバー変数、myHandPositionXとmyHandPositionYに格納します。
  8. 右手の位置、状態、そして追跡の精度を引数にして、DrawHandStateを実行します。

カラーフレーム到着時のイベント

リスト5:MainWindow.xaml.vbの一部、リスト4の続き

Private Sub myColorFrameReader_FrameArrived(sender As Object, e As ColorFrameArrivedEventArgs)
    Dim colorFramePorcessed As Boolean = False
    Using myColorFrame As ColorFrame = e.FrameReference.AcquireFrame (1)
        If myColorFrame Is Nothing = False Then   (2)
            Dim myColorFrameDescription As FrameDescription = myColorFrame.FrameDescription   (3)
            If myColorFrameDescription.Width = colorBitmap.PixelWidth AndAlso myColorFrameDescription.Height = colorBitmap.PixelHeight Then   (4)
                If myColorFrame.RawColorImageFormat = ColorImageFormat.Bgra Then
                    myColorFrame.CopyRawFrameDataToArray(ColorImagePixelData)    (5)
                Else
                    myColorFrame.CopyConvertedFrameDataToArray(ColorImagePixelData, ColorImageFormat.Bgra)    (6)
                End If
                colorFramePorcessed = True   (7)
            End If
        End If
    End Using
    If colorFramePorcessed = True Then
        colorBitmap.WritePixels(New Int32Rect(0, 0, colorBitmap.PixelWidth, colorBitmap.PixelHeight), ColorImagePixelData, colorBitmap.PixelWidth * BytesPerPixel, 0)    (8)
        roomImage.Source = colorBitmap    (9)
    End If
End Sub
  1. e.FrameReference.AcquireFrameメソッドでカラーフレームを取得し、myColorFrameで参照します。
  2. myColorFrameにデータがあった場合の処理です。
  3. KinectSensor から、イメージフレームのプロパティを取得し、変数myColorFrameDescriptionで参照します。
  4. 取得したプロパティのWidthとHeightが、それぞれcolorBitmapのPixelWidth、PixelHeightと同じであった場合の処理を行います。
  5. カラー フレーム データの形式がBgraであった場合は、CopyRawFrameDataToArrayメソッドで、Raw フレームのデータ指定された配列(ColorImagePixelData)にコピーします。
  6. そうでない場合は、CopyConvertedFrameDataToArrayメソッドで、フレームからBGRA形式のバイト列に変換し、バイト配列に格納します。
  7. Boolean型で宣言していた変数colorFrameProcessedをTrueで初期化します。
  8. colorFrameProcessed変数がTrueであった場合は、

colorBitmap(WriteableBitmapクラス)のWritePixelsメソッドで、ビットマップの指定した領域内のピクセルを更新します。CopyConvertedFrameDataToArrayメソッドとWritePixelsメソッドの書式については、第3回目を参照してください。9.roomImageのSourceプロパティにcolorBitmapオブジェクトを指定します。これでRGBカメラからの画像が表示されます。

関節の位置に透明の円を表示する処理

リスト6:MainWindow.xaml.vbの一部、リスト5の続き

Private Sub DrawEllipse(myJoint As Joint, R As Integer, myBrush As Brush)
    Dim myEllipse = New Ellipse
    With myEllipse
        .Width = R
        .Height = R
        .Fill = myBrush
    End With

    point = myKinect.CoordinateMapper.MapCameraPointToDepthSpace(myJoint.Position)   (1)
    If point.X < 0 OrElse point.Y < 0 Then
        Return
    End If
    Canvas.SetLeft(myEllipse, point.X - (R / 2))    (2)
    Canvas.SetTop(myEllipse, point.Y - (R / 2))
    If myJoint.JointType = JointType.HandRight Then
        commonJoint.JointType = JointType.HandRight
        If flag = True Then
            myImage.Margin = New Thickness(point.X, point.Y, 0, 0)    (3)
        End If
        '.Margin = New Thickness(point.X, point.Y, 0, 0)
    End If
    CanvasBody.Children.Add(myEllipse)
End Sub

直径10ピクセルで透明の円を作成します。直径はDrawEllipseを呼ぶ際に指定しています(リスト4)。

  1. CoordinateMapper.MapCameraPointToDepthSpaceメソッドで、関節の位置を、カメラ空間から距離空間へのポイントにマップし、メンバー変数pointで参照します。
  2. SetLeftとSetTopメソッドで透明な円を、指定したXとY軸に描きます。
  3. 関節のタイプが右手であり、変数flagがTrue、つまり手の形がグーの場合は、myImageオブジェクトをPoint.XとPoint.Yの位置に移動します。これにより、リンゴをつかんで移動します。変数flagの初期化は、後述のDrawHandState(リスト7)の中で行っています。プレイヤーには透明な円で関節の位置が表示されていますが、目には見えません。

プレイヤーの手の形によって条件分岐を行う処理

リスト7:MainWindow.xaml.vbの一部、リスト6の続き

Private Sub DrawHandState(joint As Joint, state As HandState, myTrackingConfidence As TrackingConfidence)
    If myTrackingConfidence <> TrackingConfidence.High Then
        Return
    End If

    If state = HandState.Open Then   (1)
        flag = False
    ElseIf state = HandState.Closed Then   (2)
        appleCanvas.Children.Clear()
        Image1.Source = Nothing
        myImage.Margin = New Thickness(point.X, point.Y, 0, 0)
        appleCanvas.Children.Add(myImage)
        flag = True   (3)
    End If
End Sub
  1. 手がパーの状態なら、flagにFalseを代入します。
  2. 手がグーの状態の場合は、リンゴが表示されていた領域をクリアし、新しく移動された位置にリンゴを表示します。
  3. flagにTrueを代入します。

ウインドウが閉じられる場合の処理

リスト8:MainWindow.xaml.vbの一部、リスト7の続き

Private Sub MainWindow_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
    If myKinect Is Nothing = False Then
        myKinect.Close()
        myKinect = Nothing
    End If
End Sub
End Class

Kinectが動作している場合は、Kinectを閉じ、全ての関連付けから解放します。

実際にプログラムを動作させると下記の動画のようになります。リンゴをつかんで動かしている感じがお分かりいただけると思います。

この記事のキーワード :

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored

ClickHouse Cloudが実現した広告運用SaaS「ATOM」のデータ基盤革新、パフォーマンスを向上しながら、運用負荷とコストを削減 11月11日 6:20 AIで開発が加速する時代、品質保証はどう変わる? Tricentisが示すAIエージェント活用の実像 11月9日 6:45 悪用までの猶予が「1分」に迫るフロンティアAI時代に開発と本番を貫く脆弱性管理が必要 10月29日 8:30 欧州CRA対応とSBOM運用。AI生成コードのOSS混入問題の対策とは ――スニペット単位で検出する「FossID」「Insignary Clarity」によるSBOM運用 9月16日 6:40 PostgreSQLからTiDBへ、稼働中SaaSで進める段階的DB移行の実践と再設計への展望 9月7日 6:30 機能安全開発におけるGoogleTestの活用を支援!「Parasoft C/C++test CT」で実現する効率化&AI連携 4月14日 6:30 【CNDW2025】Grafanaが明かす「オブザーバビリティの哲学」ー最小限の労力で実用的なインサイトを得るには 1月23日 6:30 【CNDW2025】プロダクト急増に備える基盤刷新 ーウェルスナビがECSからEKSへの移行で得た知見とは 1月15日 6:30 【CNDW2025】250環境を5人で運用、構築時間は30分に ーKINTOテクノロジーズが語るインフラ基盤組織の作り方 2025年12月18日 6:30 新たな自動化で熱視線! AIエージェントの「推論能力」を支える2つのコンポーネントとは? 2025年11月28日 6:30