Kinect記事第二回です。
前回は、サンプルプログラムを動かすところまでをやりました。
今回は実際にプログラミングでKinectを扱ってみましょう!
ってな感じでサンプルプログラムを置いておきます。
/*
Kinect の RGBカメラ画像を表示するプログラム
*/
#include<Windows.h>
#include<MSR_NuiApi.h>//KinectSDK利用時にinclude
#include<opencv2\opencv.hpp>//今回はOpenCVを利用します。
//各種libファイルの設定
#pragma comment(lib,"MSRKinectNUI.lib")
#ifdef _DEBUG
#pragma comment(lib,"opencv_core220d.lib")
#pragma comment(lib,"opencv_highgui220d.lib")
#else
//Releaseモードの場合
#pragma comment(lib,"opencv_core220.lib")
#pragma comment(lib,"opencv_highgui220.lib")
#endif
//ハンドル
HANDLE m_hNextVideoFrameEvent;
HANDLE m_pVideoStreamHandle;
//RGBデータ
cv::Ptr<IplImage> RGBImage;
//RGBデータを取得する関数
int GetRGBImage();
int main(){
//Kinectの初期化関数
NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR);
//各ハンドルの設定
m_hNextVideoFrameEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_pVideoStreamHandle = NULL;
//RGBカメラストリームの設定
HRESULT hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR , NUI_IMAGE_RESOLUTION_640x480 , 0 , 2 , m_hNextVideoFrameEvent , &m_pVideoStreamHandle );
if( FAILED( hr ) ) return -1;//取得失敗
//OpenCVの設定
cvNamedWindow("Kinect RGB Image",CV_WINDOW_AUTOSIZE);
RGBImage = cvCreateImage( cvSize (640, 480) , IPL_DEPTH_8U , 4);
while(cvWaitKey(10)!='\q'){
//次のRGBフレームが来るまで待機
WaitForSingleObject(m_hNextVideoFrameEvent,INFINITE);
//取得をする
if(GetRGBImage()==-1)return -2;
//表示
cvShowImage ("Kinect RGB Image",RGBImage);
}
cvDestroyAllWindows();
NuiShutdown();
return 0;
}
int GetRGBImage(){
//フレームを入れるクラス
const NUI_IMAGE_FRAME * pImageFrame = NULL;
HRESULT hr = NuiImageStreamGetNextFrame(m_pVideoStreamHandle, 30 , &pImageFrame );
if( FAILED( hr ) ) return -1;//取得失敗
//フレームから画像データの取得
NuiImageBuffer * pTexture = pImageFrame->pFrameTexture;
//ここからオマジナイ
KINECT_LOCKED_RECT LockedRect;
pTexture->LockRect( 0, &LockedRect, NULL, 0 );
if( LockedRect.Pitch != 0 ){
//pBitsに画像データが入っている
BYTE * pBuffer = (BYTE*) LockedRect.pBits;
memcpy(RGBImage->imageData,pBuffer,RGBImage->widthStep*RGBImage->height);
}
hr = NuiImageStreamReleaseFrame( m_pVideoStreamHandle, pImageFrame );
if( FAILED( hr ) ) return -1;//取得失敗
return 0;
}
以上のプログラムの実行結果はこのようになります。
モザイクがなんか犯罪者みたいだね!
さて、それではプログラムの詳しい説明をしていきます。
・include
#include<MSR_NuiApi.h>//KinectSDK利用時にinclude
KinectSDKを利用する場合はMSR_NuiApi.hをincludeします
・初期化関数
//Kinectの初期化関数
NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR);
Kinectの初期化関数となります。
引数に入れるフラグは以下のとおり
- NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX
- プレイヤーインデックス付きデプスマップを取得する場合
- NUI_INITIALIZE_FLAG_USES_COLOR
- NUI_INITIALIZE_FLAG_USES_SKELETON
- NUI_INITIALIZE_FLAG_USES_DEPTH
- プレイヤーインデックスのないデプスマップを使う場合
これらのフラグを|(OR)でつなげて引数にいれます。
たとえば、スケルトントラッキングとプレイヤー付きデプスを使う場合
NUI_INITIALIZE_FLAG_USES_SKELETON | NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX
のように指定します。
・ハンドル設定
//各ハンドルの設定
m_hNextVideoFrameEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_pVideoStreamHandle = NULL;
各ハンドルを設定していきます。
意味のわからない人はオマジナイ程度で!
・RGBカメラの初期設定
//RGBカメラストリームの設定
HRESULT hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR , NUI_IMAGE_RESOLUTION_640x480 , 0 , 2 , m_hNextVideoFrameEvent , &m_pVideoStreamHandle );
if( FAILED( hr ) ) return -1;//取得失敗
カメラの初期設定を行います。 RGBカメラ、深度センサ共にNuiImageStreamOpenを利用して初期化をします。
第一引数には取得する画像の種類を指定します。主なものとしては
- NUI_IMAGE_TYPE_COLOR
- NUI_IMAGE_TYPE_DEPTH
- NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX
などがあります。
・待機処理
//次のRGBフレームが来るまで待機
WaitForSingleObject(m_hNextVideoFrameEvent,INFINITE);
画像が取得されるまで待機します。
もちろん、プログラムの作り方によっては待機しないほうがいい場合もあります。
・画像取得
int GetRGBImage(){
//フレームを入れるクラス
const NUI_IMAGE_FRAME * pImageFrame = NULL;
HRESULT hr = NuiImageStreamGetNextFrame(m_pVideoStreamHandle, 30 , &pImageFrame );
if( FAILED( hr ) ) return -1;//取得失敗
//フレームから画像データの取得
NuiImageBuffer * pTexture = pImageFrame->pFrameTexture;
//ここからオマジナイ
KINECT_LOCKED_RECT LockedRect;
pTexture->LockRect( 0, &LockedRect, NULL, 0 );
if( LockedRect.Pitch != 0 ){
//pBitsに画像データが入っている
BYTE * pBuffer = (BYTE*) LockedRect.pBits;
memcpy(RGBImage->imageData,pBuffer,RGBImage->widthStep*RGBImage->height);
}
hr = NuiImageStreamReleaseFrame( m_pVideoStreamHandle, pImageFrame );
if( FAILED( hr ) ) return -1;//取得失敗
return 0;
}
この部分で重要な関数はこれです。
・NuiImageStreamGetNextFrame(m_pVideoStreamHandle, 30 , &pImageFrame );
で、画像のフレームを取得します。
第一引数は設定したストリームハンドル。
第二引数は画像が取得できてない場合に何ms待つか
第三引数は、画像情報が入るフレームのポインタとなります。
ImageFrameのメンバであるpFrameTextureを取得したのち
pFrameTextureのメンバ関数であるLockRectを呼び出します。
現時点ではこの辺はオマジナイ的なものみたいなので、キニシナイで大丈夫。(あとで色々実装されていくみたいです。)
KINECT_LOCKED_RECTのメンバであるpBitsに画像情報が入ってますのでOpenCVで使うIplImageにmemcpyしてあげて、表示させてあげれば画像情報を表示できます。
と、こんな感じでRGB表示ができるようになりました。わかりましたか?
よくわからない!って所があればコメント等どうぞです。
次回は、プレイヤー+デプスマップの取得をしたいと思います。
0 件のコメント:
コメントを投稿