Microsoft kinect SDK を手っ取り早く使ってみるミニマムプログラム 〜スケルトン編〜

Microsoftkinect SDK をダウンロードしてくると,インストールは簡単だし,Visual Studio でサンプルプログラムを簡単にコンパイルして実行できる.しかし,コードはそれなりに煩雑で(と言っても1000行程度だが),自分でアプリを作る場合にどこから始めればいいか,今一つピンとこない.

そこで,GUIなどを一切使わず,単にkinectでスケルトン (skeleton) を計測してファイルに保存するだけ,という最小のプログラムを書いてみた.言語は C++.基本的には,このページの内容をそのまま流用している.

準備

ケルトン取得プログラム

さて,次が本番.

  • 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 番目のブロック(この場合はフレーム)のみプロットするという指定.