ソースコード
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;
}
}
}
}
}