Natural Software

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

Kinect for Windows SDK v2.0 でカラー画像を取得する

Kinect for Windows SDK v2.0入門 目次

早速カラー画像を取得して表示する方法について解説します。Kinect for Windows v2のカラー画像は1920x1080の Full HD の解像度になり、従来に比べて非常にきれいになっています。

環境

筆者の環境は次の通りです。

実行結果

カラー画像を表示します。

スクリーンショット 2014-07-18 12.47.50

解説

Kinect SDK v2ではカラーやDepthなど多くのデータが、言語を問わず、同じ方法で取得できるようになっています。

カラー画像であればKinectSensor(クラス)を起点に、ColorFrameSource取得、そこからColorFrameReaderを開きます。ColorFrameReaderのデータが更新されるとColorFrameを取得でき、そこから実際のデータ(カラー画像であればRGBデータ)を取得します。

カラー画像を扱う際の解像度(幅、高さなど)はFrameDescriptionで扱います。ただし、カラー画像のデフォルトが2バイトのデータ(Bayerデータ)なので、RGB画像の解像度、データがほしい場合には指定する必要があります。

初期化

初期化の手順は次の通りです

  1. Kinectを開く
  2. カラー画像の情報を作成する(ここではBGRAフォーマット)
  3. カラーリーダーを開く

まず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#ではイベントハンドラになりますが、大きな流れは同じです。

  1. カラーフレームを取得する
  2. カラー画像のデータを取得する
  3. カラー画像のデータを表示する

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構造になっているので、言語、環境をまたいでも非常に簡単に以降できます。

Kinect for Windows SDK v2.0入門 目次