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

Natural Software

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

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

Kinect for Windows v2

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入門 目次