XNAでKINECT!

KIENCTを解析していて、XNAでも動いたらいいなとおもってやってみた。

今回はボーンの位置情報のみを取得するプログラムのみです。

(画像処理系とか期待してたらスミマセン)

実行環境は

windows 7

Visual Studio 2008

OpenNI 1.0.0.25

Prime Sense 1.3.017

をつかってやってみます。

OpenNI1.0.0.25ではサンプルに、C#によって作られているUserTracker.netというサンプルがあり、こいつを解読してXNAに実装していきます。

(2012/03/08)

KINECT for Windows SDK を用いて、XNA上でKinectを動かす方法を記述しました。

KINECT Tips

とりあえずUserTracker.netのサンプルを実行してみると

こんな感じに映ります。(右腕のボーンが消えちゃってますね・・・)

動かす事が出来たらさっそくXNAに実装していきましょう。

プロジェクトの設定

説明が解り難いかも知れないので、プロジェクトの作成からはじめて、画像多めで説明していきます。

1.

まずVisual Studioを立ち上げ新規プロジェクトを作成しましょう。

VisualC#からXNA Game Studioを選び、Windowsゲームを選択。プロジェクト名に名前を付けてOKで作成されます。

作られるプロジェクトは、参照されているフォルダ内に生成されます。(デフォルトなら、マイドキュメント/Visual Studioフォルダ/Projects/にあるはずです)

2.

作られたプロジェクトフォルダ内にOpenNI.net.dllをコピーしておきます。

(OpenNI.net.dllは c:Program Files/OpneNI/bin/ 内にあります)

そうしたらプロジェクトの参照設定を右クリックして、参照の追加。参照タブを選択し、OpenNI.net.dllを追加。

(Contentのなかにある参照設定ではないので注意!)

参照されているなら下図のようになります。

プロジェクトのセットはこれで完了です。

3.

ここからプログラミングです。サンプルのソースを参考に行っていきます。

なお参考にしているソースは、Samples/UserTracker.net/MainWindow.csです。

まず、using xn; と宣言しましょう。これでOpenNIの変数を使えるようになります。

次に変数の宣言・初期化を行います。

using xn;

namespace ○○○○○○

{

public class Game1 : Microsoft.Xna.Framework.Game

{

// 宣言

private Context context;

private DepthGenerator depthGenerator; // 深度

private UserGenerator userGenerator; //

private PoseDetectionCapability poseDetectionCapability; // キャリブレーションの認識

private SkeletonCapability skeletonCapability; //

private string calibPose; // キャリブレーションポーズの情報

private Dictionary<uint, Dictionary<SkeletonJoint, SkeletonJointPosition>> joints; // ジョイントの情報

public Game1()

{

// 初期化

context = new Context("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);

skeletonCapability = new SkeletonCapability(userGenerator);

skeletonCapability.CalibrationEnd += new SkeletonCapability.CalibrationEndHandler(skeletonCapbility_CalibrationEnd);

skeletonCapability.SetSkeletonProfile(SkeletonProfile.All);

calibPose = skeletonCapability.GetCalibrationPose();

joints = new Dictionary<uint, Dictionary<SkeletonJoint, SkeletonJointPosition>>();

userGenerator.StartGenerating();

・・・

のように宣言しておきます。最低限この変数のみでKINECTの情報は取得できます。

さて、このままの状態だと userGenerator_NewUser 、 userGenerator_LostUse 等がありませんと警告が出ていると思います。

サンプルソースを下へ少しスクロールすると・・・

// キャリブレーションが完了しトラッキングをするか

void skeletonCapbility_CalibrationEnd(ProductionNode node, uint id, bool success)

{

if (success)

{

skeletonCapability.StartTracking(id);

joints.Add(id, new Dictionary<SkeletonJoint, SkeletonJointPosition>());

}

else

{

this.poseDetectionCapability.StartPoseDetection(calibPose, id);

}

}

// キャリブレーションの認識

void poseDetectionCapability_PoseDetected(ProductionNode node, string pose, uint id)

{

poseDetectionCapability.StopPoseDetection(id);

skeletonCapability.RequestCalibration(id, true);

}

// 新しいユーザの検出

void userGenerator_NewUser(ProductionNode node, uint id)

{

poseDetectionCapability.StartPoseDetection(this.calibPose, id);

}

// ユーザの消滅(ロスト)

void userGenerator_LostUser(ProductionNode node, uint id)

{

joints.Remove(id);

}

それらしいものがつらつらと書かれています。これはユーザーが新しく現れたり、キャリブレーションポーズをしたりなどのイベントを認識する、イベントハンドラです。

これで初期化は完了です。

次に、KINECTから情報をもらってきましょう。

KINECTの情報を得るには

try

{

// 深度の更新

context.WaitOneUpdateAll(depthGenerator);

}

catch (Exception)

{

}

// 認識しているユーザ数

uint[] users = userGenerator.GetUsers();

foreach (uint user in users)

{

// キャリブレーションしているか

if (skeletonCapability.IsCalibrated(user))

{

// 各ユーザのジョイント情報を取得

GetJoints(user);

}

}

をUpDate内に記述してあげます。さて、これで情報は取得できたはずです。さっそく実行してみましょう。

エラーが出たのならば、dllの参照やプログラムをもう一度確認しましょう。

動いたならばとりあえずはOKです。しかし、お気づきの方もいるかもしれませんがものすごく処理が重いです。

原因はKINECTとXNAのFPSの違いです。KINECTは30[fps]、XNAは標準で60[fps]でうごいていて、XNAの更新速度にKINECT側が追い付いていけないのが原因かと思われます。(個人的な見解です)

よって、XNA側を30[fps]にするなどして更新速度を下げてあげれば快適に動くはずです。