Members‎ > ‎Wataru-Fujimura‎ > ‎Kinect Tips‎ > ‎

XNAによる骨格情報の取得

XNAでの骨格情報取得方法です。
(作成日:2012/03/01)


1.プロジェクトを作る

実画像取得と同じように作成してください。


2.参照設定を追加

実画像取得と同じように作成してください。



3.テクスチャの追加

今回は下のpng画像を用いて骨格情報を表示します。

          

画像をプロジェクトに設定します。
png画像を作成したプロジェクトの[〇〇〇Content]ファイルにおいてください。



その後、ソリューションエクスプローラーの[〇〇〇Content]を右クリックし[追加]→[既存の項目]



画像を選択して[追加]ボタンでプロジェクトに追加します。



追加されるとこのように表示されます。




4.プログラミング

以下のコードのように入力してください。

Game1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

// kinectのセンサクラス
// Microsoft.kinectを参照設定に追加
using Microsoft.Kinect;

/// <summary>
/// XY座標に変換した骨格情報
/// </summary>
struct mySkeleton
{
    /// <summary>
    /// 画面上での骨格の位置
    /// </summary>
    public Vector2[] position;

    /// <summary>
    /// 骨格の認識状態
    /// </summary>
    public SkeletonTrackingState skeletonState;

    /// <summary>
    /// 初期化
    /// </summary>
    public void Initialize()
    {
        position = new Vector2[20];
        skeletonState = SkeletonTrackingState.NotTracked;
    }
};

namespace xnagetskeleton
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        /// <summary>
        /// 実画像テクスチャ
        /// 640x480
        /// </summary>
        private Texture2D imageTexture;

        /// <summary>
        /// kinectから取得したRGBデータ
        /// (byte型配列)
        /// </summary>
        private byte[] imageData;

        /// <summary>
        /// 骨格情報
        /// </summary>
        private Skeleton[] skeletonData;

        /// <summary>
        /// ユーザーの骨格情報
        /// </summary>
        private mySkeleton[] userSkeleton;
        
        /// <summary>
        /// KINECTのセンサクラス
        /// </summary>
        private KinectSensor kinect;

        /// <summary>
        /// 骨格情報を表す円の画像
        /// </summary>
        Texture2D pointTexture;

        /// <summary>
        /// キーボードの状態
        /// </summary>
        private KeyboardState key;

        /// <summary>
        /// 1frame前のキーボードの状態
        /// </summary>
        private KeyboardState oldkey;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            // ウィンドウサイズの指定
            graphics.PreferredBackBufferHeight = 480;
            graphics.PreferredBackBufferWidth = 640;
        }

        protected override void Initialize()
        {
            // 骨格情報配列の初期化
            userSkeleton = new mySkeleton[2];
            userSkeleton[0].Initialize();
            userSkeleton[1].Initialize();

            // kinectの初期化
            kinect = KinectSensor.KinectSensors[0];

            // カラー画像の取得を開始する
            kinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(ColorImageReady);
            kinect.ColorStream.Enable(ColorImageFormat.YuvResolution640x480Fps15);
            
            // スケルトントラッキングを開始する
            kinect.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(SkeletonFrameReady);
            kinect.SkeletonStream.Enable();

            // Kinectを起動する
            kinect.Start();

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // 新規の SpriteBatch を作成します。これはテクスチャーの描画に使用できます。
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // テクスチャの読み込み
            pointTexture = Content.Load<Texture2D>("point");

        }

        protected override void UnloadContent() { }

        protected override void Update(GameTime gameTime)
        {
            // キーボードの状態を取得
            key = Keyboard.GetState();

            // Escapeキーが押されたらプログラムを終了する
            if (key.IsKeyDown(Keys.Escape))
                Exit();

            // F1が押されたら[ウィンドウモード⇔フルスクリーンモード]の切り替え
            if (key.IsKeyDown(Keys.F1) && oldkey.IsKeyUp(Keys.F1))
                graphics.ToggleFullScreen();

            // このフレームのキーボードの状態を記憶しておく
            oldkey = key;

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // スプライトバッチの使用開始
            spriteBatch.Begin();

            // 実画像の描写
            if (imageTexture != null)
                spriteBatch.Draw(imageTexture, new Vector2(0, 0), null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);

            // 骨格の描画
            if (skeletonData != null)
            {
                // 1人目の骨格
                if (userSkeleton[0].skeletonState == SkeletonTrackingState.Tracked)
                {
                    for (int i = 0; i < userSkeleton[0].position.Length; i++)
                        // テクスチャの中心を骨格の位置に合わせるため、縦横のサイズの半分を引いておく
                        spriteBatch.Draw(pointTexture, new Vector2(userSkeleton[0].position[i].X - pointTexture.Width / 2, userSkeleton[0].position[i].Y - pointTexture.Height / 2), Color.Red);
                }

                // 2人目の骨格
                if (userSkeleton[1].skeletonState == SkeletonTrackingState.Tracked)
                {
                    for (int i = 0; i < userSkeleton[1].position.Length; i++)
                        // テクスチャの中心を骨格の位置に合わせるため、縦横のサイズの半分を引いておく
                        spriteBatch.Draw(pointTexture, new Vector2(userSkeleton[1].position[i].X - pointTexture.Width / 2, userSkeleton[1].position[0].Y - pointTexture.Height / 2), Color.Red);
                }
            }

            // スプライトバッチの使用終了
            spriteBatch.End();

            base.Draw(gameTime);
        }

        /// <summary>
        /// カラー画像の取得
        /// </summary>
        void ColorImageReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            // kinectからカラーイメージを取得
            ColorImageFrame image = e.OpenColorImageFrame();

            if (image != null)
            {
                // imageData配列の初期化
                imageData = new byte[image.PixelDataLength];

                // imageのピクセルデータをpixelDataへコピーする
                image.CopyPixelDataTo(imageData);

                int no = 0;

                // 入れ替え用
                byte temp = 0;

                for (int y = 0; y < image.Height; y++)
                {
                    for (int x = 0; x < image.Width; x++, no += 4)
                    {
                        // BGRAからRGBAに変換する
                        temp = imageData[no];
                        imageData[no] = imageData[no + 2];
                        imageData[no + 2] = temp;

                        // Alphaを255にする
                        imageData[no + 3] = 255;
                    }
                }

                // imageTextureの初期化
                imageTexture = new Texture2D(GraphicsDevice, image.Width, image.Height);

                // imageTextureにimageDataを反映する
                imageTexture.SetData(imageData);
            }
        }

        /// <summary>
        /// 骨格情報を取得する
        /// </summary>
        void SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            SkeletonFrame skeleton = e.OpenSkeletonFrame();

            if (skeleton != null)
            {
                // skeletonDataの初期化
                skeletonData = new Skeleton[skeleton.SkeletonArrayLength];

                // kinectから取得した骨格情報をコピー
                skeleton.CopySkeletonDataTo(skeletonData);

                int userIndex = 0;

                // 骨格情報の取得
                foreach (var userJoin in skeletonData)
                {
                    int jointIndex = 0;

                    if (userJoin.TrackingState == SkeletonTrackingState.Tracked)
                    {
                        userSkeleton[userIndex].skeletonState = SkeletonTrackingState.Tracked;

                        foreach (Joint join in userJoin.Joints)
                        {
                            // カラー画像のサイズにに合わせて骨格情報をXY座標に変換する
                            ColorImagePoint point = kinect.MapSkeletonPointToColor(join.Position, kinect.ColorStream.Format);

                            userSkeleton[userIndex].position[jointIndex].X = point.X;
                            userSkeleton[userIndex].position[jointIndex].Y = point.Y;

                            jointIndex++;
                        }

                        userIndex++;
                    }
                    else
                        userSkeleton[userIndex].skeletonState = SkeletonTrackingState.NotTracked;
                }
            }
        }
    }
}





実行結果

このような感じで表示されるはずです(頭の位置は表示されていません)。
ユーザー認識は6人までできますが、骨格情報が取得できるのは2人までのようです。



画像のサイズに合ったXY座標変換は、深度画像のサイズに合わせても行うことができます。

座標変換

// カラー画像のサイズにに合わせて骨格情報をXY座標に変換する
ColorImagePoint point = kinect.MapSkeletonPointToColor(join.Position, kinect.ColorStream.Format);

                  ↓  ↓

// 深度画像のサイズにに合わせて骨格情報をXY座標に変換する
DepthImagePoint point = kinect.MapSkeletonPointToDepth(join.Position, kinect.DepthStream.Format);


また、3次元座標が直接ほしい場合は「 join.Position 」から取得できます。


ċ
xnagetskeleton.zip
(66k)
Wataru Fujimura,
Mar 1, 2012, 2:02 AM
Comments