Microsoft kinect SDK を手っ取り早く使ってみるミニマムプログラム 〜スケルトン編〜
Microsoft の kinect SDK をダウンロードしてくると,インストールは簡単だし,Visual Studio でサンプルプログラムを簡単にコンパイルして実行できる.しかし,コードはそれなりに煩雑で(と言っても1000行程度だが),自分でアプリを作る場合にどこから始めればいいか,今一つピンとこない.
そこで,GUIなどを一切使わず,単にkinectでスケルトン (skeleton) を計測してファイルに保存するだけ,という最小のプログラムを書いてみた.言語は C++.基本的には,このページの内容をそのまま流用している.
準備
- Visual Studio は各自で用意して頂く.
- Kinect for Windows SDK v1.0 Beta 2 をインストールする.もっと新しいのが出てたら,そちらでもよいと思う.
- 試しに,インストールしたディレクトリ (e.g. C:\Program Files\Microsoft SDKs\Kinect\v1.0 Beta2) 以下にあるC++のサンプル (e.g. C:\Program Files\Microsoft SDKs\Kinect\v1.0 Beta2\Samples\KinectSDKSamples.zip\Unmanaged\SkeletalViewer) を Visual Studio でコンパイルしてみて,ちゃんと実行までできるか確認しておく.
- このディレクトリ以下のファイル一式を適当なディレクトリにコピーし,SkeletalViewer.sln を Visual Studio で起動
- (記憶が曖昧だが)ソリューションエクスプローラで SkeletalViewer のプロパティを開き,C/C++ の全般で「追加のインストールディレクトリ」に C:\Program Files\Microsoft SDKs\Kinect\v1.0 Beta2\inc を追加
- 同じく,リンカの全般で「追加のライブラリディレクトリ」に C:\Program Files\Microsoft SDKs\Kinect\v1.0 Beta2\lib\x86 を追加
- ビルドして kinect をつなぎ,実行すれば,カメラ画像,デプス,スケルトンが取得されるはず
スケルトン取得プログラム
さて,次が本番.
- Visual Studio で空のCUIプロジェクトを作って,以下のプログラムを書く.これ以外の余計なヘッダとかソースは一切不要(あってもいいが).
#include <tchar.h> #include <iostream> #include <fstream> #include <windows.h> #include <MSR_NuiApi.h> #include <MSR_NuiSkeleton.h> using namespace std; bool connect() { HRESULT hr= NuiInitialize(NUI_INITIALIZE_FLAG_USES_SKELETON); if(FAILED(hr)) { cout<<"kinect is not initialized!! KINECT connected?"<<endl; return false; } return true; } int _tmain(int argc, _TCHAR* argv[]) { connect(); ofstream outfs("test1.dat"); NUI_SKELETON_FRAME SkeletonFrame; while (true) { NuiSkeletonGetNextFrame(0, &SkeletonFrame); for(int i(0); i<NUI_SKELETON_COUNT; ++i) { if(SkeletonFrame.SkeletonData[i].eTrackingState==NUI_SKELETON_TRACKED) { float hand_l_x=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_LEFT].x; float hand_l_y=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_LEFT].y; float hand_l_z=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_LEFT].z; float hand_r_x=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT].x; float hand_r_y=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT].y; float hand_r_z=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT].z; cout<<"Left Hand: "<<hand_l_x<<", "<<hand_l_y<<", "<<hand_l_z<<"\t"; cout<<"Right Hand:"<<hand_r_x<<", "<<hand_r_y<<", "<<hand_r_z<<endl; for(int j(0);j<NUI_SKELETON_POSITION_COUNT; ++j) { outfs<<SkeletonFrame.SkeletonData[i].SkeletonPositions[j].x <<" "<<SkeletonFrame.SkeletonData[i].SkeletonPositions[j].y <<" "<<SkeletonFrame.SkeletonData[i].SkeletonPositions[j].z<<endl; } outfs<<endl; } } // smooth out the skeleton data NuiTransformSmooth(&SkeletonFrame,NULL); } return 0; }
- ソリューションエクスプローラでプロジェクトのプロパティを開き,C/C++ の全般で「追加のインストールディレクトリ」に C:\Program Files\Microsoft SDKs\Kinect\v1.0 Beta2\inc を追加
- 同じく,リンカの全般で「追加のライブラリディレクトリ」に C:\Program Files\Microsoft SDKs\Kinect\v1.0 Beta2\lib\x86 を追加
- 同じく,リンカの入力で「追加の依存ファイル」に MSRKinectNUI.lib を追加
- ビルド
エラーが出なければ,kinect をつないで実行しよう.
スケルトンが取得できるように kinect から少し離れると,手先位置の出力が始まる.
以下はコマンドプロンプトの出力.
Attempting to open \\?\usb#vid_045e&pid_02ae#a00364915929052a#{00873fdf-61a8-11d 1-ef5e-00c04f2d728b}\00 KinWinDeviceName = (\\?\usb#vid_045e&pid_02ae#a00364915929052a#{00873fdf-61a8-11 d1-ef5e-00c04f2d728b}\00\PIPE01) KinectCamera_OpenStreamEndpoint Opened successfully. Left Hand: 0.274473, -0.800708, 3.15295 Right Hand:0.564601, -0.655808, 3.0679 Left Hand: 0.279375, -0.868915, 3.152 Right Hand:0.305756, -0.57561, 3.17116 Left Hand: 0.286445, -0.831477, 3.15941 Right Hand:0.563111, -0.737451, 3.13431 ...
また,同時に,アプリケーションのディレクトリに test1.dat という名前のファイルが作成され,すべてのマーカの3次元位置が記録されているので確認してみよう.
この test1.dat を gnuplot でプロットすると,
gnuplot> set size ratio 1 gnuplot> plot "test1.dat" ev :::200::200 pt 7 ps 10 t ""
以下のような画像が見られるはず.ちなみに ev :::200::200 は 200 番目のブロック(この場合はフレーム)のみプロットするという指定.