KOSAKA LABORATORY->Tips

Kinect 骨格情報の取得 その1

 前回で 
   を、終えました。
  今回からは、実際にKinectを用いて骨格情報を取得してみたいと思います。  

ソースプログラム
   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using Microsoft.Xna.Framework;
   5:  using Microsoft.Xna.Framework.Audio;
   6:  using Microsoft.Xna.Framework.Content;
   7:  using Microsoft.Xna.Framework.GamerServices;
   8:  using Microsoft.Xna.Framework.Graphics;
   9:  using Microsoft.Xna.Framework.Input;
  10:  using Microsoft.Xna.Framework.Media;
  11:  using xn;    //OpenNIの読み込み
  12:   
  13:  namespace FirstKinect{
  14:    public class Game1 : Microsoft.Xna.Framework.Game{
  15:      GraphicsDeviceManager graphics;
  16:      SpriteBatch spriteBatch;
  17:   
  18:      #region Kinect必要変数宣言
  19:      private Context context;
  20:      private DepthGenerator  depthGenerator;            // 深度 深さ Generator
  21:      private UserGenerator  userGenerator;            // ユーザ  Generator
  22:      private PoseDetectionCapability poseDetectionCapability;  // キャリブレーションの認識
  23:      private SkeletonCapability skeletonCapability;        // 骨格
  24:      private string calibPose;                  //                                                  // キャリブレーションポーズの情報
  25:      private Dictionary<uint, Dictionary<SkeletonJoint, SkeletonJointPosition>> joints;  // ジョイント情報
  26:      private SkeletonJointPosition[] SkeletonJointData = new SkeletonJointPosition[16];  //骨格情報
  27:      #endregion
  28:   
  29:      #region Game1
  30:      public Game1(){
  31:        graphics = new GraphicsDeviceManager(this);
  32:        Content.RootDirectory = "Content";
  33:   
  34:        #region 初期化と設定
  35:        context = new Context(@"C:\Program Files (x86)\OpenNI\Data\SamplesConfig.xml");
  36:        depthGenerator = context.FindExistingNode(NodeType.Depth) as DepthGenerator;
  37:   
  38:   
  39:        //UserGenerator設定
  40:        userGenerator = new UserGenerator(context);
  41:        userGenerator.NewUser += 
  42:              new UserGenerator.NewUserHandler(userGenerator_NewUser);
  43:        userGenerator.LostUser +=
  44:              new UserGenerator.LostUserHandler(userGenerator_LostUser);
  45:   
  46:        //PoseDetectionCapability設定
  47:        poseDetectionCapability = new PoseDetectionCapability(userGenerator);
  48:        poseDetectionCapability.PoseDetected +=
  49:              new PoseDetectionCapability.PoseDetectedHandler
  50:                         (poseDetectionCapability_PoseDetected);
  51:   
  52:        //SkeletonCapability設定
  53:        skeletonCapability = new SkeletonCapability(userGenerator);
  54:        skeletonCapability.CalibrationEnd +=
  55:              new SkeletonCapability.CalibrationEndHandler(skeletonCapbility_CalibrationEnd);
  56:        skeletonCapability.SetSkeletonProfile(SkeletonProfile.All);
  57:   
  58:        calibPose = skeletonCapability.GetCalibrationPose();
  59:   
  60:        //ジョイント設定
  61:        joints = new Dictionary<uint, Dictionary<SkeletonJoint, SkeletonJointPosition>>();
  62:   
  63:        //UserGeneratorの開始
  64:        userGenerator.StartGenerating();
  65:        #endregion
  66:      }
  67:      #endregion
  68:   
  69:      #region 初期化
  70:      protected override void Initialize(){
  71:        base.Initialize();
  72:      }
  73:      #endregion
  74:   
  75:      #region 読み込み処理
  76:      protected override void LoadContent(){
  77:        spriteBatch = new SpriteBatch(GraphicsDevice);
  78:      }
  79:      #endregion
  80:   
  81:      #region 破棄処理
  82:      protected override void UnloadContent(){
  83:      }
  84:      #endregion
  85:   
  86:      #region 描画以外の処理 毎フレーム実行
  87:      protected override void Update(GameTime gameTime)
  88:      {
  89:   
  90:        #region ゲームパットでの終了処理
  91:        if(GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed){
  92:          this.Exit();
  93:        }
  94:        #endregion
  95:   
  96:        #region Kinectの値を取得
  97:   
  98:        try{
  99:          context.WaitOneUpdateAll(depthGenerator);  // 深度の更新を待つ
 100:         }catch (Exception){
 101:         }
 102:    
 103:        uint[] users = userGenerator.GetUsers();    // 検出ユーザ数の取得
 104:        Console.WriteLine("検出人数:"+users.Length);
 105:   
 106:        foreach (uint user in users){
 107:          if (skeletonCapability.IsCalibrated(user)){  //トラッキング出来るかどうか
 108:             GetJoints(user);            //ジョイント情報を取得
 109:              Console.WriteLine("頭:"+SkeletonJointData[0].position.X + ","+
 110:                          SkeletonJointData[0].position.Y + ","+
 111:                          SkeletonJointData[0].position.Z );
 112:          }
 113:        }
 114:        #endregion
 115:   
 116:        base.Update(gameTime);
 117:      }
 118:      #endregion
 119:   
 120:      #region 描写処理 毎フレーム実行
 121:      protected override void Draw(GameTime gameTime){
 122:        GraphicsDevice.Clear(Color.CornflowerBlue);
 123:        base.Draw(gameTime);
 124:      }
 125:      #endregion
 126:   
 127:      #region Kinect処理関係
 128:      // キャリブレーションが完了しトラッキングするかどうか
 129:        #region skeletonCapbility_CalibrationEnd
 130:        void skeletonCapbility_CalibrationEnd(ProductionNode node, uint id, bool success){
 131:            if (success){
 132:              skeletonCapability.StartTracking(id);
 133:              joints.Add(id, new Dictionary<SkeletonJoint, SkeletonJointPosition>());
 134:            }else{
 135:              this.poseDetectionCapability.StartPoseDetection(calibPose, id);
 136:            }
 137:          }
 138:        #endregion
 139:   
 140:        // キャリブレーションの認識
 141:        #region poseDetectionCapability_PoseDetected
 142:        void poseDetectionCapability_PoseDetected(ProductionNode node, string pose, uint id){
 143:          poseDetectionCapability.StopPoseDetection(id);
 144:          skeletonCapability.RequestCalibration(id, true);
 145:        }
 146:        #endregion
 147:   
 148:        // 新しいユーザの検出
 149:        #region userGenerator_NewUser
 150:        void userGenerator_NewUser(ProductionNode node, uint id){
 151:          poseDetectionCapability.StartPoseDetection(this.calibPose, id);
 152:        }
 153:        #endregion
 154:   
 155:        // ユーザの消滅(ロスト)
 156:        #region userGenerator_LostUser
 157:        void userGenerator_LostUser(ProductionNode node, uint id){
 158:          joints.Remove(id);
 159:        }
 160:        #endregion
 161:   
 162:        #region GetJonts 骨格情報の取得
 163:        private void GetJoints(uint user){
 164:          GetJoint(user, SkeletonJoint.Head, 0);      //【頭】
 165:          GetJoint(user, SkeletonJoint.Neck, 1);      //【首】
 166:          GetJoint(user, SkeletonJoint.LeftShoulder, 2);  //【左肩】
 167:          GetJoint(user, SkeletonJoint.LeftElbow, 3);   //【左ひじ】
 168:          GetJoint(user, SkeletonJoint.LeftHand, 4);    //【左手】
 169:          GetJoint(user, SkeletonJoint.RightShoulder, 5); //【右肩】
 170:          GetJoint(user, SkeletonJoint.RightElbow, 6);  //【右ひじ】
 171:          GetJoint(user, SkeletonJoint.RightHand, 7);   //【右手】
 172:          GetJoint(user, SkeletonJoint.Torso, 8);     //【胴】
 173:          GetJoint(user, SkeletonJoint.LeftHip, 9);     //【左尻】
 174:          GetJoint(user, SkeletonJoint.LeftKnee, 10);   //【左膝】
 175:          GetJoint(user, SkeletonJoint.LeftFoot, 11);   //【左足首】
 176:          GetJoint(user, SkeletonJoint.RightHip, 12);   //【右尻】
 177:          GetJoint(user, SkeletonJoint.RightKnee, 13);  //【右膝】
 178:          GetJoint(user, SkeletonJoint.RightFoot, 14);  //【右足首】
 179:   
 180:          if (SkeletonJointData[9].fConfidence != 0 && SkeletonJointData[12].fConfidence != 0){ //【下腹部】
 181:            #region 下腹部を計算により求める。
 182:              SkeletonJointData[15] = SkeletonJointData[9];
 183:              SkeletonJointData[15].position.X = 0.5f * (SkeletonJointData[9].position.X + SkeletonJointData[12].position.X);
 184:              SkeletonJointData[15].position.Y = 0.5f * (SkeletonJointData[9].position.Y + SkeletonJointData[12].position.Y);
 185:              SkeletonJointData[15].position.Z = 0.5f * (SkeletonJointData[9].position.Z + SkeletonJointData[12].position.Z);
 186:            #endregion
 187:          }
 188:        }
 189:        #endregion
 190:   
 191:        #region GetJont 各ジョイントの取得
 192:        private void GetJoint(uint user, SkeletonJoint joint, int k){
 193:          SkeletonJointPosition pos = new SkeletonJointPosition();
 194:          this.skeletonCapability.GetSkeletonJointPosition(user, joint, ref pos);
 195:          if (pos.position.Z == 0){
 196:            pos.fConfidence = 0;
 197:          }else{
 198:            pos.position = this.depthGenerator.ConvertRealWorldToProjective(pos.position);
 199:          }
 200:          this.joints[user][joint] = pos;
 201:          SkeletonJointData[k] = pos; //pos.fConfidenceも含めて保存される
 202:        }
 203:        #endregion
 204:   
 205:      #endregion
 206:   
 207:    }
 208:  }
次のプロプラムは、骨格情報を検出できると、検出できた人数と、頭の座標(X,Y,Z)座標をコンソールに返します。

●実行結果
fk08.jpg
 骨格情報を取得検出できると、頭の座標データが送られてきます。
画面にはカメラの映像も何も表示されないので、OpenNIのサンプルを動かし、骨格情報が検出できるカメラの位置、人の立ち位置を確認した状態でプログラムを動かすようにしてください。

解説
 解説するほどではありませんが、骨格情報が取得できるとSkeletonJointPosition配列に三次元の座標が格納されます。SkeletonJointPositionの配列番号と関節の関係を次の図に示します。
fk09.jpg
参考サイト