ドキュメントを読んでいて、公式SDKは簡単に複数Kinectを扱えるようなので試してみました。
今のところの制約事項。
ソース
ざっとこんな感じで、ソースが適当なのはご愛嬌。ここではINuiInstanceをラップしたクラスを使ってるので、INuiInstanceをベタで使った場合のサンプルも作った作ろう(たぶん。。。)
複数Kinectを扱う場合は、C++ではINuiInstanceを使うようだが、C#を見る限りINuiInstance一択でも良さそう。ただ、ドキュメントには、単体の場合はNuiXxxを使った方がいいよ的な記述も見られます(自分の英語力では読み取れない)。
素のAPI版
ソースはこちら
// 複数のKinectのカメラ画像を表示する #include <iostream> #include <sstream> #include <vector> // MSR_NuiApi.hの前にWindows.hをインクルードする #include <Windows.h> #include <MSR_NuiApi.h> #include <opencv2/opencv.hpp> #define ERROR_CHECK( ret ) \ if ( ret != S_OK ) { \ std::cout << "failed " #ret " " << ret << std::endl; \ exit( 1 ); \ } struct Runtime { INuiInstance* kinect; // Kinectのインスタンス HANDLE imageEvent; // データの更新イベントハンドル HANDLE streamHandle; // 画像データのハンドル std::string windowName; // 表示するウィンドウの名前 cv::Ptr< IplImage > image; // 表示データ }; void main() { try { const NUI_IMAGE_RESOLUTION resolution = NUI_IMAGE_RESOLUTION_640x480; // アクティブなKinectの数を取得する int kinectCount = 0; ERROR_CHECK( ::MSR_NUIGetDeviceCount( &kinectCount ) ); // Kinectのインスタンスを生成する typedef std::vector< Runtime > Runtimes; Runtimes runtime( kinectCount ); for ( int i = 0; i < runtime.size(); ++i ) { // Kinectのインスタンス生成と初期化 ERROR_CHECK( ::MSR_NuiCreateInstanceByIndex( i, &runtime[i].kinect ) ); runtime[i].kinect->NuiInitialize( NUI_INITIALIZE_FLAG_USES_COLOR ); runtime[i].imageEvent = ::CreateEvent( 0, TRUE, FALSE, 0 ); ERROR_CHECK( runtime[i].kinect->NuiImageStreamOpen( NUI_IMAGE_TYPE_COLOR, resolution, 0, 2, runtime[i].imageEvent, &runtime[i].streamHandle ) ); // ウィンドウ名を作成 std::stringstream ss; ss << "malti_kinect " << (i + 1); runtime[i].windowName = ss.str(); // 画面サイズを取得 DWORD x = 0, y = 0; ::NuiImageResolutionToSize( resolution, x, y ); // OpenCVの初期設定 runtime[i].image = ::cvCreateImage( cvSize( x, y ), IPL_DEPTH_8U, 4 ); ::cvNamedWindow( runtime[i].windowName.c_str() ); } bool continue_ = true; while ( continue_ ) { for ( Runtimes::iterator it = runtime.begin(); it != runtime.end(); ++it ) { // データの更新を待つ ::WaitForSingleObject( it->imageEvent, INFINITE ); // カメラデータの取得 CONST NUI_IMAGE_FRAME *imageFrame = 0; ERROR_CHECK( it->kinect->NuiImageStreamGetNextFrame( it->streamHandle, 0, &imageFrame ) ); // 画像データの取得 KINECT_LOCKED_RECT rect; imageFrame->pFrameTexture->LockRect( 0, &rect, 0, 0 ); // データのコピーと表示 memcpy( it->image->imageData, (BYTE*)rect.pBits, it->image->widthStep * it->image->height ); ::cvShowImage( it->windowName.c_str(), it->image ); // カメラデータの解放 ERROR_CHECK( it->kinect->NuiImageStreamReleaseFrame( it->streamHandle, imageFrame ) ); int key = ::cvWaitKey( 10 ); if ( key == 'q' ) { continue_ = false; } } } // 終了処理 for ( Runtimes::iterator it = runtime.begin(); it != runtime.end(); ++it ) { it->kinect->NuiShutdown(); } ::cvDestroyAllWindows(); } catch ( std::exception& ex ) { std::cout << ex.what() << std::endl; } }
ラッパー版
ソースはこちら
// 複数のKinectのカメラ画像を表示する #include <iostream> #include <sstream> #include <vector> #include "kinect\nui\kinect.h" #include "kinect\nui\ImageFrame.h" #include <opencv2/opencv.hpp> struct Runtime { std::shared_ptr< kinect::nui::Kinect > kinect; std::string windowName; cv::Ptr< IplImage > image; Runtime( int index, const std::string& name ) : kinect( new kinect::nui::Kinect( index ) ) , windowName( name ) { } }; void main() { try { std::vector< Runtime > runtime; for ( int i = 0; i < kinect::nui::Kinect::GetActiveCount(); ++i ) { std::stringstream ss; ss << "malti_kinect " << (i + 1); Runtime instance( i, ss.str().c_str() ); instance.kinect->Initialize( NUI_INITIALIZE_FLAG_USES_COLOR ); instance.kinect->VideoStream().Open( NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480 ); instance.image = ::cvCreateImage( cvSize(instance.kinect->VideoStream().Width(), instance.kinect->VideoStream().Height()), IPL_DEPTH_8U, 4 ); ::cvNamedWindow( instance.windowName.c_str() ); runtime.push_back( instance ); } bool continue_ = true; while ( continue_ ) { for ( std::vector< Runtime >::iterator it = runtime.begin(); it != runtime.end(); ++it ) { // データの更新を待つ it->kinect->WaitAndUpdateAll(); // 次のフレームのデータを取得して表示する kinect::nui::VideoFrame videoMD( it->kinect->VideoStream() ); memcpy( it->image->imageData, (BYTE*)videoMD.Bits(), videoMD.Pitch() * videoMD.Height() ); ::cvShowImage( it->windowName.c_str(), it->image ); int key = ::cvWaitKey( 10 ); if ( key == 'q' ) { continue_ = false; } } } ::cvDestroyAllWindows(); } catch ( std::exception& ex ) { std::cout << ex.what() << std::endl; } }