KinectとC#で骨格情報を取得してみる

| コメント(1) | トラックバック(2) このエントリーを含むはてなブックマーク

Kinectというマイクロソフトから販売されたXbox 360向けのゲームデバイスでプレイヤーの位置、動き、声、顔を認識することができたりする。このデバイスを知って、自分は XBox 360 を持っていませが、思わず欲しくなってしまったので、購入しました。

今回は、このkinectの本当の凄いところである骨格情報について取得してみようと思う。

きっかけ

OpenNI のサイトが更新され、ソフトウェアも更新されていました。

unstable版も出て OpenNIのC#バインディングなども出てきたみたいなので、こちらを試してみました。

参照指定

"C:\Program Files\OpenNI\Bin\OpenNI.net.dll" が新たに追加されています。 このアセンブリを参照設定してください。

参照設定
参照設定 posted by (C)k1ha410

コード

今回は、Windows Form でプロジェクトを作りました。コンソールベースでもよいのですが、 骨格情報とか出力する上でこちらを採用しました。 (今回は表示コードまで記載していません)

初期化コード

using xn;
public partial class Form1 : Form
{
    Context context;
    DepthGenerator depthGenerator;
    UserGenerator userGenerator;
    PoseDetectionCapability poseDetectionCapability;
    SkeletonCapability skeletonCapbility;

    public Form1()
    {
        InitializeComponent();
        context = new Context(@"C:\Program Files\OpenNI\Data\SamplesConfig.xml");
        depthGenerator = context.FindExistingNode(NodeType.Depth) as DepthGenerator;

        userGenerator = new UserGenerator(context);
        userGenerator.NewUser += new UserGenerator.NewUserHandler(userGenerator_NewUser);
        userGenerator.LostUser += new UserGenerator.LostUserHandler(userGenerator_LostUser);

        poseDetectionCapability = new PoseDetectionCapability(userGenerator);
        poseDetectionCapability.PoseDetected += new PoseDetectionCapability.PoseDetectedHandler(poseDetectionCapability_PoseDetected);

        skeletonCapbility = new SkeletonCapability(userGenerator);
        skeletonCapbility.CalibrationEnd += new SkeletonCapability.CalibrationEndHandler(skeletonCapbility_CalibrationEnd);
        skeletonCapbility.SetSkeletonProfile(SkeletonProfile.All);


        userGenerator.StartGenerating();

        OpenNiThread = new Thread(new ThreadStart(OpenNiLoop));
        OpenNiThread.Start();
    }
 
 

上記コードで以下のような事をしました。

  1. xn.Context の作成 (context)
  2. xn.DepthGeneratorの取得 (depthGenerator)
  3. xn.UserGeneratorの作成 (userGenerator)
  4. 新しいユーザの検出、ユーザのロストイベントの追加(userGenerator.NewUser,userGenerator.LostUser)
  5. xn.PoseDetectionCapabilityの生成(poseDetectionCapability)
  6. ポーズ検出イベントの追加(poseDetectionCapability.PoseDetected)
  7. xn.SkeletonCapabilityの生成(skeletonCapbility)
  8. ガッツボーズ[キャリブレーション]の検出イベントの追加(skeletonCapbility.CalibrationEnd)
  9. SkeletonProfileの設定
  10. userGeneratorの開始
  11. OpenNi用のスレッド開始

これで初期設定が終わりました。

スレッドのメイン処理

次に、OpenNi用のスレッドの処理です

    void OpenNiLoop()
    {
        while (!isDone)
        {
            var updated = false;
            try
            {   //1.深度センサー用ジェネレータの更新の待ち
                this.context.WaitOneUpdateAll(depthGenerator);
            }
            catch (Exception)
            {
            }
            //2.検出済みユーザー数の取得
            var users = userGenerator.GetUsers();
            foreach (uint user in users)
            {
                Console.WriteLine("User id {0}", user);
                //3.検出ユーザがトラッキングできてるか?
                if (skeletonCapbility.IsTracking(user))
                {
                    //ここでスケルトン情報が取得できます
                }
            }
        }
    }
 
 

どのようにスケルトン情報を取得するかというと、 次のようなコードで取得できます。

SkeletonJointPosition Joint(uint user, SkeletonJoint joint)
{
    var pos = new SkeletonJointPosition();
    skeletonCapbility.GetSkeletonJointPosition(user, joint, ref pos);
    if (pos.position.Z == 0)
    {
        pos.fConfidence = 0;
    }
    else
    {
        pos.position = depthGenerator.ConvertRealWorldToProjective(pos.position);
    }
    return pos;
}
 
 

第一引数のuserは、先ほどトラッキングできたか調べていたユーザidです。

SkeletonJointとは

  • SkeletonJoint.Head(頭)
  • SkeletonJoint.Neck(首)
  • SkeletonJoint.LeftShoulder(左肩)
  • SkeletonJoint.LeftElbow(左肘(ひじ))
  • SkeletonJoint.LeftHand(左手)
  • SkeletonJoint.RightShoulder(右肩)
  • SkeletonJoint.RightElbow(右肘(ひじ))
  • SkeletonJoint.RightHand(右手)
  • SkeletonJoint.Torso(胴)
  • SkeletonJoint.LeftHip(左尻)
  • SkeletonJoint.LeftKnee(左膝(ひざ))
  • SkeletonJoint.LeftFoot(左足)
  • SkeletonJoint.RightHip(右尻)
  • SkeletonJoint.RightKnee(右膝(ひざ))
  • SkeletonJoint.RightFoot(右足)

などです。詳しくはSkeletonJointを参照ください。

SkeletonJointPosition.positionが、Point3Dを返却するので、 このX,Y,Zで各部位の座標を取得する事が出来ます。

イベントハンドラ

    void userGenerator_NewUser(ProductionNode node, uint id)
    {//新しいユーザを検出した時
        System.Diagnostics.Trace.WriteLine(String.Format("New User {0}", id));
        //新しいユーザのポーズ検出を開始します
        poseDetectionCapability.StartPoseDetection(skeletonCapbility.GetCalibrationPose(), id);
    }

    void userGenerator_LostUser(ProductionNode node, uint id)
    {//ユーザをロストした時
        System.Diagnostics.Trace.WriteLine(String.Format("Lost User {0}", id));
    }

    void poseDetectionCapability_PoseDetected(ProductionNode node, string pose, uint id)
    {//ガッツボーズを検出した時
        System.Diagnostics.Trace.WriteLine(String.Format("PoseDetected {1} {0}", id, pose));
        //新しいユーザのポーズ検出を終了し
        poseDetectionCapability.StopPoseDetection(id);
        //キャリブレーションを開始します
        skeletonCapbility.RequestCalibration(id, true);
    }

    void skeletonCapbility_CalibrationEnd(ProductionNode node, uint id, bool success)
    {//キャリブレーション完了した時
        System.Diagnostics.Trace.WriteLine(String.Format("CalibrationEnd {1} {0}", id, success));
        if (success)
        {//成功したなら、トラッキング開始
            skeletonCapbility.StartTracking(id);
        }
        else
        {//失敗したなら、再度検出開始
            poseDetectionCapability.StartPoseDetection(skeletonCapbility.GetCalibrationPose(), id);
        }
    }
 
 

上記のようにすることで、ユーザの各部位の位置情報が取得できます

おわりに

上記のように、Kinectでユーザの骨格情報が取得できます。かなりの粒度で値が 取得できるので、色々なことに応用できるかと思います。

楽天さんの紹介

これを見て、Kinect買ってみたいという方は 以下をチェックしてみてはいかがでしょうか?

(楽天さんのサイトです)

トラックバック(2)

トラックバックURL: http://www.m-tea.info/mt-tb.cgi/88

骨格情報ナイス! C#やってないけど・・・ 続きを読む

オンラインゲーム作っちゃうかぁ(;´ρ`) [改め、オンラインゲームエディター作っちゃうかぁ(゚Д゚)] - OpenNI.Net (2011年3月23日 09:29)

C++でOpenNIを操作するプログラムを書いたがうまくいかなかった。というのも、スレッドの処理に戸惑ったせいで、描画がおかしくなってしまったのだ、でも、... 続きを読む

コメント(1)

TEAと申します
C#のキネクトのソースが大変参考になりました
ありがとうございます
失礼ですが、参考になさった資料などあれば乗せて頂けると助かります
画面に取り込んだイメージを表示しようとして
苦労しているもので・・・

コメントする

あわせて読みたいブログパーツ

このブログ記事について

このページは、k1ha410が2011年2月 5日 15:22に書いたブログ記事です。

ひとつ前のブログ記事は「Hokuriku.NET vol 5に参加してきました」です。

次のブログ記事は「雨どいを修繕してみた」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。