Kinect for Windows SDK v2.0入門 目次
早速カラー画像を取得して表示する方法について解説します。Kinect for Windows v2のカラー画像は1920x1080の Full HD の解像度になり、従来に比べて非常にきれいになっています。
環境
筆者の環境は次の通りです。
- Windows 8.1 Pro Update1 64bit
- Visual Studio 2013 Ultimate(Express for Windows Desktopでも可)
- Kinect for Windows SDK v2.0-1409
- 32bitアプリケーション
- サンプルコードのリポジトリ
実行結果
カラー画像を表示します。
解説
Kinect SDK v2ではカラーやDepthなど多くのデータが、言語を問わず、同じ方法で取得できるようになっています。
カラー画像であればKinectSensor(クラス)を起点に、ColorFrameSource取得、そこからColorFrameReaderを開きます。ColorFrameReaderのデータが更新されるとColorFrameを取得でき、そこから実際のデータ(カラー画像であればRGBデータ)を取得します。
カラー画像を扱う際の解像度(幅、高さなど)はFrameDescriptionで扱います。ただし、カラー画像のデフォルトが2バイトのデータ(Bayerデータ)なので、RGB画像の解像度、データがほしい場合には指定する必要があります。
初期化
初期化の手順は次の通りです
- Kinectを開く
- カラー画像の情報を作成する(ここではBGRAフォーマット)
- カラーリーダーを開く
まずKinectを開きます。
続いてColorFrameSourceを使ってFrameDescriptionを作成します。前述のとおり、カラーデータのデフォルトがRGBデータではないので、新規に作成する必要があります。作成したDescriptionを使ってビットマップやバッファの作成を行います。
最後にカラーリーダーを作成し、データの読み込み準備を行います。データの読み込みは、C++ではポーリング、C#ではイベントハンドラの登録を行います。
C++
void initialize(){
// デフォルトのKinectを取得する
ERROR_CHECK( ::GetDefaultKinectSensor( &kinect ) );
// Kinectを開く
ERROR_CHECK( kinect->Open() );
BOOLEAN isOpen = false;
ERROR_CHECK( kinect->get_IsOpen( &isOpen ) );
if ( !isOpen ){
throw std::runtime_error("Kinectが開けません");
}
// カラーリーダーを取得する
ComPtr<IColorFrameSource> colorFrameSource;
ERROR_CHECK( kinect->get_ColorFrameSource( &colorFrameSource ) );
ERROR_CHECK( colorFrameSource->OpenReader( &colorFrameReader ) );
// カラー画像のサイズを取得する
ComPtr<IFrameDescription> colorFrameDescription;
ERROR_CHECK( colorFrameSource->CreateFrameDescription(
ColorImageFormat::ColorImageFormat_Bgra, &colorFrameDescription ) );
ERROR_CHECK( colorFrameDescription->get_Width( &colorWidth ) );
ERROR_CHECK( colorFrameDescription->get_Height( &colorHeight ) );
ERROR_CHECK( colorFrameDescription->get_BytesPerPixel( &colorBytesPerPixel ) );
// バッファーを作成する
colorBuffer.resize( colorWidth * colorHeight * colorBytesPerPixel );
}
C#(デスクトップ)
private void Window_Loaded( object sender, RoutedEventArgs e ){
try {
// Kinectを開く
kinect = KinectSensor.GetDefault();
if ( kinect == null ) {
throw new Exception("Kinectを開けません");
}
kinect.Open();
// カラー画像の情報を作成する(BGRAフォーマット)
colorFrameDesc = kinect.ColorFrameSource.CreateFrameDescription( ColorImageFormat.Bgra );
// カラーリーダーを開く
colorFrameReader = kinect.ColorFrameSource.OpenReader();
colorFrameReader.FrameArrived += colorFrameReader_FrameArrived;
}
catch ( Exception ex ) {
MessageBox.Show( ex.Message );
Close();
}
}
C#(Windows ストアアプリ)
protected override void OnNavigatedTo( NavigationEventArgs e ){
base.OnNavigatedTo( e );
try {
// Kinectを開く
kinect = KinectSensor.GetDefault();
if ( kinect == null ) {
throw new Exception( "Kinectを開けません" );
}
kinect.Open();
// カラー画像の情報を作成する(BGRAフォーマット)
colorFrameDesc = kinect.ColorFrameSource.CreateFrameDescription( ColorImageFormat.Bgra );
colorBitmap = new WriteableBitmap( colorFrameDesc.Width, colorFrameDesc.Height );
ImageColor.Source = colorBitmap;
colorBuffer = new byte[colorFrameDesc.Width * colorFrameDesc.Height * colorFrameDesc.BytesPerPixel];
// カラーリーダーを開く
colorFrameReader = kinect.ColorFrameSource.OpenReader();
colorFrameReader.FrameArrived += colorFrameReader_FrameArrived;
}
catch ( Exception ex ) {
MessageDialog dlg = new MessageDialog( ex.Message );
dlg.ShowAsync();
}
}
データの取得
続いてデータを取得し表示します。C++ではポーリング、C#ではイベントハンドラになりますが、大きな流れは同じです。
- カラーフレームを取得する
- カラー画像のデータを取得する
- カラー画像のデータを表示する
C++
void updateColorFrame(){
// フレームを取得する
ComPtr<IColorFrame> colorFrame;
auto ret = colorFrameReader->AcquireLatestFrame( &colorFrame );
if ( ret == S_OK ){
// BGRAの形式でデータを取得する
ERROR_CHECK( colorFrame->CopyConvertedFrameDataToArray(
colorBuffer.size(), &colorBuffer[0], ColorImageFormat::ColorImageFormat_Bgra ) );
// カラーデータを表示する
cv::Mat colorImage( colorHeight, colorWidth, CV_8UC4, &colorBuffer[0] );
cv::imshow( "Color Image", colorImage );
// スマートポインタを使ってない場合は、自分でフレームを解放する
// colorFrame->Release();
}
}
C#(デスクトップ)
void colorFrameReader_FrameArrived( object sender, ColorFrameArrivedEventArgs e ){
// カラーフレームを取得する
using ( var colorFrame = e.FrameReference.AcquireFrame() ) {
if ( colorFrame == null ) {
return;
}
// BGRAデータを取得する
colorBuffer = new byte[colorFrameDesc.Width * colorFrameDesc.Height * colorFrameDesc.BytesPerPixel];
colorFrame.CopyConvertedFrameDataToArray( colorBuffer, ColorImageFormat.Bgra );
// ビットマップにする
ImageColor.Source = BitmapSource.Create( colorFrameDesc.Width, colorFrameDesc.Height, 96, 96,
PixelFormats.Bgra32, null, colorBuffer, colorFrameDesc.Width * (int)colorFrameDesc.BytesPerPixel );
}
}
C#(Windows ストアアプリ)
void colorFrameReader_FrameArrived( ColorFrameReader sender, ColorFrameArrivedEventArgs args ){
// カラーフレームを取得する
using ( var colorFrame = args.FrameReference.AcquireFrame() ) {
if ( colorFrame == null ) {
return;
}
// BGRAデータを取得する
colorFrame.CopyConvertedFrameDataToArray( colorBuffer, ColorImageFormat.Bgra );
// ビットマップにする
var stream = colorBitmap.PixelBuffer.AsStream();
stream.Write( colorBuffer, 0, colorBuffer.Length );
colorBitmap.Invalidate();
}
}
C++についてはCOMのインタフェースを使っているため、使い終わったらcolorFrame->Release();のように参照カウンタの解放が必要になります。Visual Studio Pro以上であれば CComPtrというATLのクラスがあるので、それを使えばよいですが、Expressの場合ATLがありません。そこで機能を単純化した「ComPtrクラス」を作成してあります。これを使うとデストラクタでReleaseを行うため、リソースリークがなくなります。
まとめ
このようにKinect for Windows v2はv1と比較して、同じかより簡単に記述できるようになりました。
また、C#についてはデスクトップ、Windowsストアアプリが同じAPI構成になっているため、フレームワークの使い方を除けば、同じコードになっていることがわかります。
C++についてもv1と違い、C#と同じきれいなAPI構造になっているので、言語、環境をまたいでも非常に簡単に以降できます。