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 」から取得できます。