XNAによる骨格情報の取得
画像をプロジェクトに設定します。
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 」から取得できます。