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

XNAによる認識人物の実画像取得

XNAでの認識人物の実画像取得方法です。
(作成日:2012/03/01)


windowsフォームアプリの時のように、ユーザーに色付けのところで実画像のデータのRGBを挿入すればおわりです。





実行結果






ソースコード

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;

//////////////////////////////////////////////////
// 参照設定にPresentationCoreを設定しておくこと //
// (深度画像処理に使うため)                   //
//////////////////////////////////////////////////

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

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

        /// <summary>
        /// kinectから取得した深度データ
        /// (short型配列)
        /// </summary>
        private short[] depthData;

        /// <summary>
        /// 認識人物の実画像テクスチャ
        /// 640x480
        /// </summary>
        private Texture2D userTexture;

        /// <summary>
        /// 深度データから色情報に変換されたデータ
        /// (byte型配列)
        /// </summary>
        private byte[] userImageData;
        
        /// <summary>
        /// ビットシフトに用いる
        /// </summary>
        private static readonly int Bgr32BytesPerPixel = (System.Windows.Media.PixelFormats.Bgr32.BitsPerPixel + 7) / 8;

        /// <summary>
        /// 深度データを配列に挿入する順番
        /// </summary>
        private const int RedIndex = 0;
        private const int GreenIndex = 1;
        private const int BlueIndex = 2;
        private const int AlphaIndex = 3;

        /// <summary>
        /// KINECTのセンサクラス
        /// </summary>
        private KinectSensor kinect;

        /// <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()
        {
            // kinectの初期化
            kinect = KinectSensor.KinectSensors[0];

            // カラー画像の取得を開始する
            kinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(ColorImageReady);
            kinect.ColorStream.Enable(ColorImageFormat.YuvResolution640x480Fps15);

            // 深度画像の取得を開始する
            kinect.DepthFrameReady += new EventHandler<DepthImageFrameReadyEventArgs>(DepthFrameReady);
            kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);

            // スケルトントラッキングを開始する
            kinect.SkeletonStream.Enable();

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

            base.Initialize();
        }

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

        }

        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 (userTexture != null)
                spriteBatch.Draw(userTexture, new Vector2(0, 0), null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);

            // スプライトバッチの使用終了
            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;
                    }
                }
            }
        }

        /// <summary>
        /// 深度画像の取得
        /// </summary>
        void DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            // kinectから深度情報を取得
            DepthImageFrame depthImage = e.OpenDepthImageFrame();

            if (depthImage != null)
            {
                // depthDataの初期化
                depthData = new short[depthImage.PixelDataLength];
                userImageData = new byte[depthImage.Width * depthImage.Height * Bgr32BytesPerPixel];

                // depthImageのピクセルデータをdepthDataへコピーする
                depthImage.CopyPixelDataTo(depthData);

                // 深度ごとに色づけを行う
                ConvertDepthFrame(depthData, ((KinectSensor)sender).DepthStream);

                // depthTextureの初期化
                userTexture = new Texture2D(GraphicsDevice, depthImage.Width, depthImage.Height);

                // depthTextureにuserImageDataを反映する
                userTexture.SetData(userImageData);
            }
        }

        /// <summary>
        /// 深度ごとに色づけ&認識ユーザーの色づけ
        /// </summary>
        private void ConvertDepthFrame(short[] depthFrame, DepthImageStream depthStream)
        {
            for (int i16 = 0, i32 = 0; i16 < depthFrame.Length && i32 < this.userImageData.Length; i16++, i32 += 4)
            {
                int player = depthFrame[i16] & DepthImageFrame.PlayerIndexBitmask;
                int realDepth = depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth;

                // 13ビットの深度情報を表示に適した8ビットへ変換する(最上位ビットを無視する)
                byte intensity = (byte)(~(realDepth >> 4));

                // 認識ユーザーの実画像を取得する
                if (player != 0)
                {
                    userImageData[i32 + RedIndex] = imageData[i32 + RedIndex];
                    userImageData[i32 + GreenIndex] = imageData[i32 + GreenIndex];
                    userImageData[i32 + BlueIndex] = imageData[i32 + BlueIndex];
                    userImageData[i32 + AlphaIndex] = 255;
                }
            }
        }
    }
}

ċ
xnagetuserimage.zip
(60k)
Wataru Fujimura,
Mar 1, 2012, 2:03 AM
Comments