KOSAKA LABORATORY->Tips

Kinect XNAで奥行きの取得 OpenNI V1.1.041版

 前回「Kinect XNAで奥行きの取得」を解説したのですが、OpenNIをV1.1.041版にアップグレードすると仕様が変わったようで動かないので、ここで解説しておきます。


ソースプログラム
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;
using OpenNI;


namespace OpenKinect
{
 /// <summary>
 /// 基底 Game クラスから派生した、ゲームのメイン クラスです。
 /// </summary>
 public class Game1 : Microsoft.Xna.Framework.Game
 {
  GraphicsDeviceManager graphics;
  SpriteBatch spriteBatch;

  private readonly string SAMPLE_XML_FILE = @"C:\Program Files (x86)\OpenNI\Data\SamplesConfig.xml";

  Texture2D texture = null;         //テクスチャ
   private Color[] imageColor;        //色情報を格納する

  #region Kinect関係
  private Context context;
  private DepthGenerator depth;
  private UserGenerator userGenerator;
  private SkeletonCapability skeletonCapbility;
  private PoseDetectionCapability poseDetectionCapability;
  private string calibPose;
  private bool shouldRun;
  private int[] histogram;
  private DepthMetaData depthMD = new DepthMetaData();


  private Dictionary<int, Dictionary<SkeletonJoint, SkeletonJointPosition>> joints;

  private bool shouldDrawPixels = true;
  private bool shouldDrawBackground = true;
  private bool shouldPrintID = true;
  private bool shouldPrintState = true;
  private bool shouldDrawSkeleton = true;

  private Color[] colors = { Color.Red, Color.Blue, Color.ForestGreen, Color.Yellow,
           Color.Orange, Color.Purple, Color.White };
  private int ncolors = 6;

  #endregion

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


   this.TargetElapsedTime = TimeSpan.FromSeconds(1.0 / 30.0);
  }

  protected override void Initialize(){

   base.Initialize();

   #region KINECT
    this.context = new Context(SAMPLE_XML_FILE);
    this.depth = context.FindExistingNode(NodeType.Depth) as DepthGenerator;
    if (this.depth == null)
    {
     throw new Exception("Viewer must have a depth node!");
    }

    this.userGenerator = new UserGenerator(this.context);
    this.skeletonCapbility = this.userGenerator.SkeletonCapability;
    this.poseDetectionCapability = this.userGenerator.PoseDetectionCapability;
    this.calibPose = this.skeletonCapbility.CalibrationPose;

    this.userGenerator.NewUser += userGenerator_NewUser;
    this.userGenerator.LostUser += userGenerator_LostUser;
    this.poseDetectionCapability.PoseDetected += poseDetectionCapability_PoseDetected;
    this.skeletonCapbility.CalibrationEnd += skeletonCapbility_CalibrationEnd;

    this.skeletonCapbility.SetSkeletonProfile(SkeletonProfile.All);
    this.joints = new Dictionary<int,Dictionary<SkeletonJoint,SkeletonJointPosition>>();
    this.userGenerator.StartGenerating();


    this.histogram = new int[this.depth.DeviceMaxDepth];

    MapOutputMode mapMode = this.depth.MapOutputMode;

   #endregion

  }

  #region Kinect関数
   #region // キャリブレーションが完了しトラッキングするかどうか
   void skeletonCapbility_CalibrationEnd(object sender, CalibrationEndEventArgs e){
    if (e.Success){
     this.skeletonCapbility.StartTracking(e.ID);
     this.joints.Add(e.ID, new Dictionary<SkeletonJoint, SkeletonJointPosition>());
    }else{
     this.poseDetectionCapability.StartPoseDetection(calibPose, e.ID);
    }
   }
   #endregion

   #region // キャリブレーションの認識
   void poseDetectionCapability_PoseDetected(object sender, PoseDetectedEventArgs e){
    this.poseDetectionCapability.StopPoseDetection(e.ID);
    this.skeletonCapbility.RequestCalibration(e.ID, true);
   }
   #endregion

   #region 新しいユーザの検出
   void userGenerator_NewUser(object sender, NewUserEventArgs e){
    this.poseDetectionCapability.StartPoseDetection(this.calibPose, e.ID);
   }
   #endregion

   #region ユーザの消滅(ロスト)
   void userGenerator_LostUser(object sender, UserLostEventArgs e){
    this.joints.Remove(e.ID);
   }
   #endregion

   #region CalcHist
   private unsafe void CalcHist(DepthMetaData depthMD){
    // reset
    for (int i = 0; i < this.histogram.Length; ++i)
     this.histogram[i] = 0;

    ushort* pDepth = (ushort*)depthMD.DepthMapPtr.ToPointer();

    int points = 0;
    for (int y = 0; y < depthMD.YRes; ++y){
     for (int x = 0; x < depthMD.XRes; ++x, ++pDepth){
      ushort depthVal = *pDepth;
      if (depthVal != 0){
       this.histogram[depthVal]++;
       points++;
      }
     }
    }
    for (int i = 1; i < this.histogram.Length; i++){
     this.histogram[i] += this.histogram[i-1];
    }

    if (points > 0){
     for (int i = 1; i < this.histogram.Length; i++){
      this.histogram[i] = (int)(256 * (1.0f - (this.histogram[i] / (float)points)));
     }
    }
   }
   #endregion

  #endregion

  #region LoadContent
  protected override void LoadContent(){
   spriteBatch = new SpriteBatch(GraphicsDevice);
  }
  #endregion

  #region UnloadContent
  protected override void UnloadContent(){ }
  #endregion

  #region Update
  protected unsafe override void Update(GameTime gameTime){
   if(GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
    this.Exit();

   #region Kinect読み込み

   try{
    this.context.WaitOneUpdateAll(this.depth);// 深度の更新を待つ
   }catch (Exception){
   }

   this.depth.GetMetaData(depthMD);

   CalcHist(depthMD);

   #region 画像の生成
    lock (this) {
 
     ushort* pDepth = (ushort*)this.depth.DepthMapPtr.ToPointer();  //奥行のポインタ取得
     ushort* pLabels = (ushort*)this.userGenerator.GetUserPixels(0).LabelMapPtr.ToPointer();

     this.imageColor = new Color[depthMD.XRes * depthMD.YRes];
     this.texture = new Texture2D(graphics.GraphicsDevice , depthMD.XRes , depthMD.YRes); //テクスチャの作成

     //画像取得 ポインタからの情報をX,Y軸に格納していく
     for (int y = 0; y < depthMD.YRes; ++y){ //y軸
      for (int x = 0; x < depthMD.XRes; ++x, ++pDepth, ++pLabels){

       ushort label = *pLabels;
       if (this.shouldDrawBackground || *pLabels != 0){
        Color labelColor = Color.White;
         if (label != 0)
          labelColor = colors[label % ncolors];
         byte pixel = (byte)this.histogram[*pDepth];
         this.imageColor[ y*depthMD.XRes+x ] = new Color( (byte)(pixel * (labelColor.R / 256.0)),
                      (byte)(pixel * (labelColor.G / 256.0)),
                      (byte)(pixel * (labelColor.B / 256.0)) );
       }
      }
     }
     
     this.texture.SetData(this.imageColor); //textureにデータを書き込む
    }
   #endregion
   #endregion

    base.Update(gameTime);
  }
  #endregion

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


   //スプライト
   this.spriteBatch.Begin();
   this.spriteBatch.Draw(this.texture,new Vector2(0,0), Color.White); //Textureの描写
   this.spriteBatch.End();

   base.Draw(gameTime);
  }
  #endregion

 }
}