Kinect for Windows Sensor + SDK – その5 深度情報計測とスケルトンの組合せ


さてさて、その4で紹介した画像、よく見るとダブル#が…いやそうでなく、よく見ると円がありますね。これは、スケルトン情報を元に描いている円です。

ベータ版のときからのKinectセンサーユーザーなら、もうスケルトンは既知の内容で、スティックフィギュアを頭に描く人も多いでしょう。このポストでは、深度情報を計測している時に取得できるスケルトン情報を説明します。

その2(だったと思う)で、深度情報で人がいることを感知するには、SkeletonFrameをEnableにする必要があると説明しましたね。一方で深度情報は6人まで認識できますよとも説明しました。では6人識別している時のスケルトン情報って何なの…というのがこのポストの主題です。

Kinect for Windows SDKの場合、Managed APIがあって、C#であっという間にプログラミングが出来るので、理屈や説明は抜きにして、コードを書いて試してみましょう。その4までで説明してきたDepthFrameのDepthFrameReadyイベントのハンドラ内で、スケルトン情報を取り出す方法を以下に説明していきます。

スケルトン情報を取り出すのはとても簡単で、

            var skeletonStream = kinectSensor.SkeletonStream;

kinectSensor変数は、イベントハンドラの引数で渡されるsenderをもとに

            var kinectSensor = (KinectSensor)sender;

でOKです。

            using (var skeletonFrame = skeletonStream.OpenNextFrame(0))        ---- ①
            {
                if (skeletonFrame != null)        ---- ②
                {
                    Skeleton[] skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];        ---- ③
                    skeletonFrame.CopySkeletonDataTo(skeletons);        ---- ④
                    foreach (var skeleton in skeletons)         ---- ⑤
                    {
                        if (skeleton.TrackingState == SkeletonTrackingState.PositionOnly)         ---- ⑦
                        {
                            var position = skeleton.Position;         ---- ⑧
                            DrawPoint(kinectSensor, depthFrame,colorFrame, position);        ---- ⑨
                        }
                    }
                }

先ず、①でskeletonFrameから、スケルトンの各部位を取得する為のFrameを取り出します。ミドルウェア側で準備が出来ていない場合は、nullが返るので、nullチェックをきちんと行ってください(②)

そして、③でスケルトンのデータを保持するのに必要なメモリを確保し、CopySkeletonDataToメソッドで、スケルトンフレームから取り出します(④)。これは深度情報や実画像でも似たようなメソッドがありましたね。
取得したデータ群でぶん回します(⑤)。深度情報で6人Maxハンドリングの場合は、Max2人の体の部位の詳細な情報はやってきません。このときTrackingStateがPositionOnlyなものがデータとして来るんです(⑦)。skeleton変数にはその変数の状態とどこでそれを検知したかという位置情報が格納されています。⑧

⑨のメソッドの中身では、深度情報や実画像へのマップをして、何らかの描画などを行います。

その4でも説明しましたが、深度、実画像、スケルトンの座標系、画素数は異なっています。SkeletonFrameから得られた位置情報を、深度情報や、実画像と組み合わせる場合には、そこを考慮してマップする必要がある訳です。ここで、その4で紹介したマップ系のメソッドが大活躍するわけです。

深度情報にマップするには、KinectSensorのMakeSkeletonPointToDepth()メソッドを使います。⑧で得られた位置情報と、深度情報のフォーマットを渡してコールすれば、DepthImagePointという型の位置情報を取得することが出来ます。同様に実画像情報にマップするには、MapSkeletonPointToColor()メソッドを使います。同様に⑧で得られた位置情報と実画像のフォーマットを引数として渡せば、実画像上のスケルトンの部位の座標をColorImagePointの変数として得られるわけです。二つのデータ構造共にX,Yという位置情報をあらわすプロパティが用意されているので変換後の値は、それらプロパティを通じて取得が可能です。

上のコードを実行すれば人として認識されているヒトのPositionが取得できるので、例えばMapSekeletoPointDepthをコールすれば、スケルトンの座標がDepthFrameから取得したデータ列のどのデータ項目に該当するかわかるわけです。画処理のコードは煩雑なので割愛しますが、例えば実画像にスケルトン情報をマップするとすれば、該当するメソッドを使って座標を変換すると良いでしょう。そんなこんなで座標変換&取得できたPositionOnlyをちょっと加工すると、

丸が付いているのは、人として認識されている証です。ちゃんと6個の円がありますね。
私もかろうじて人として認識されているらしいという瞬間。

Comments (0)

Skip to main content