読者です 読者をやめる 読者になる 読者になる

Natural Software

KinectなどのDepthセンサーを中心に活動しています

Kinect for Windows SDK beta で遊んでみた 〜 C++でOpenCV対応、OpenNIっぽく 〜 #shibuya_ni

Kinect


金曜日にリリースされて、みなさん土日でたくさん遊んでたみたいで、若干出遅れ感があるのですが、MS Kinect公式SDKのカメラ、距離、ユーザーあたりを遊んでみました。上の画像は、カメラ画像にユーザーと骨格をマッピングしたものです。
OpenCV対応はこちらを参考にしています。ありがとうございます:-)

ここいらへんもぼちぼち更新してます

環境


OpenCVと公式SDKをデフォルトのパスでインストールして、ソースのkinect_sdk_samples.slnを開いてビルドすれば動くと思います。

やったこと

  • カメラ画像をOpenCVで表示する
  • デプスマップを表示する
  • カメラ画像に、ユーザーを重ね合わせる
  • カメラ画像に、ユーザーとボーンを重ね合わせる


公式SDKC++ライブラリは、単体で使用するときはC,複数Kinectを扱うときはCOMインタフェースを使うようです。C#のほうをみると、COMインタフェースをラップした形になっているようなので、それに合わせてC++のほうも(自分が)使いやすくしてみました。今のとこカメラとユーザーの重ね合わせはこんな感じで書けるようになっています。
結構OpenNIと似てますね。同じデバイスを使ってるので、よくよく考えると当然なのかもしれません。

// 中心の距離を表示するサンプル
#include <iostream>
#include <sstream>

#include "kinect\nui\Kinect.h"
#include "kinect\nui\ImageFrame.h"

#include <opencv2/opencv.hpp>

// ユーザーの色づけ
const UINT colors[] =
{
    0xFFFFFFFF,    // ユーザーなし
    0xFF00FFFF,
    0xFFFF00FF,
    0xFFFFFF00,
    0xFF00FF00,
    0xFF0000FF,
    0xFFFF0000,
};

void main()
{
    try {
        kinect::nui::Kinect kinect;
        kinect.Initialize( NUI_INITIALIZE_FLAG_USES_COLOR | NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON );

        kinect::nui::ImageStream& video = kinect.VideoStream();
        video.Open( NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480 );

        kinect::nui::ImageStream& depth = kinect.DepthStream();
        depth.Open( NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX, NUI_IMAGE_RESOLUTION_320x240 );

        // OpenCVの初期設定
        char* windowName = "player";
        ::cvNamedWindow( windowName );
        cv::Ptr< IplImage > playerImg = ::cvCreateImage( cvSize(video.Width(), video.Height()), IPL_DEPTH_8U, 4 );

        while ( 1 ) {
            // データの更新を待つ
            kinect.WaitAndUpdateAll();

            // 次のフレームのデータを取得する(OpenNIっぽく)
            kinect::nui::VideoFrame videoMD( video );
            kinect::nui::DepthFrame depthMD( depth );

            // データのコピーと表示
            UINT* img = (UINT*)playerImg->imageData;
            for ( int y = 0; y < videoMD.Height(); ++y ) {
                for ( int x = 0; x < videoMD.Width(); ++x, ++img ) {
                    *img = videoMD( x, y ) & colors[depthMD( x / 2, y / 2 ) & 0x7];
                }
            }

            ::cvShowImage( windowName, playerImg );

            int key = ::cvWaitKey( 10 );
            if ( key == 'q' ) {
                break;
            }
        }

        ::cvDestroyAllWindows();
    }
    catch ( std::exception& ex ) {
        std::cout << ex.what() << std::endl;
    }
}

気づいたこと

  • キャリブレーションのポーズをしないで骨格が取れるのは画期的
  • VMで動かない(おそらくわざと制限をかけている)。MacのBootCampはOK
  • Kinect SDKはカメラが1280x1024か640x480で、デプス(ユーザー検出)が320x240か80x60なので、一工夫しないと、カメラ画像にユーザーを重ねるのができない
  • ViewPointの設定がないので、カメラとデプスがずれる
  • Mirrorの設定がないので、鏡の画像しかとれない
  • RecordとPlayerがないので、記録と再生はできない
  • カメラと距離でに関しては、OpenNIのうちGeneratorとMetaData相当といった感じ(Capabilityやコールバックがない)。もちろんNITE相当もない
  • Audioをがんばりすぎて、イメージとデプスはおざなりになってる印象