Kinect for Windows v2入門 ― C++プログラマー向け連載(2)

Kinect for Windows v2入門 ― C++プログラマー向け連載(2)

Kinect v2プログラミング(C++) - Color編

2014年12月22日 改訂 (初版:2014/02/10)

Kinect SDK v2で、データを取得する基本的な流れを説明。Color画像を取得するサンプルプログラムを紹介する。正式版に合わせて改訂。

杉浦 司(Microsoft MVP for Kinect for Windows)
  • このエントリーをはてなブックマークに追加

 前回は、旧型のKinect for Windows(以下、Kinect v1)と新型のKinect for Windows(以下、Kinect v2)の仕様を比較して紹介した。

 今回からは、Kinectから各種データを取得する方法を比較しながら紹介する。

Colorカメラ

 Kinectには通常のWebカメラなどと同様にColorカメラが搭載されており、Color画像を取得できる。このColorカメラは、Kinect v1では640×480の解像度であったが、Kinect v2では1920×1080と大幅に解像度が向上している。

 今回は、Colorカメラから画像を取得する方法を紹介する。

データを取得する流れ

 Kinect SDK v1とKinect SDK v2でデータを取得する基本的な流れを図1に示す*1

  • *1 ここで示すのはあくまでも基本的な流れである。Kinect SDK v2には、複数の「Source」や「Reader」を一括して扱うAPIがあり、ここで紹介するデータを取得する流れとは少し異なることもある。
図1 Kinect SDK v1とKinect SDK v2のデータ取得の流れ

 Kinect SDK v1では、SensorからStreamを開き、StreamからFrameを取得、Frameからデータを取得するという流れであった。

 Kinect SDK v2では、SensorからSourceを取得、SourceからReaderを開き、ReaderからFrameを取得、Frameからデータを取得するという流れになった。

 Kinect SDK v2の「Source」は、Kinectから取得するColorDepthといったデータの流れごとに1つ存在する。これは、Kinect SDK v1の「Stream」と同じだ。

 Kinect SDK v2では、「Reader」というステップが追加された。「Reader」は1つの「Source」に対して複数開くことができる。この仕様により、マルチスレッドのアプリケーションでは取得したデータを別のスレッドにコピーするといった処理が不要になる、複数のアプリケーションでは同じセンサーからデータを取得できるなどの利点がある。

サンプルプログラム

 Kinect SDK v2でColor画像を取得して表示するサンプルプログラムを示す。図1で示したデータを取得するステップごとに抜粋して解説する。このサンプルプログラムの全容は、以下のページで公開している。

 このサンプルプログラムでは、画像データを扱うためにOpenCVを用いる。OpenCVの詳細は以下の情報を参照するといいだろう。

 また、Kinect SDK v1で同様にColor画像を取得して表示するサンプルプログラムは、筆者の近著『Kinect for Windows SDK実践プログラミング』を参照していただきたい。

「Sensor」

 Sensorを取得する。

C++
// Sensor
IKinectSensor* pSensor;   //……1
HRESULT hResult = S_OK;
hResult = GetDefaultKinectSensor( &pSensor );  //……2
if( FAILED( hResult ) ){
  std::cerr << "Error : GetDefaultKinectSensor" << std::endl;
  return -1;
}

hResult = pSensor->Open();  //……3
if( FAILED( hResult ) ){
  std::cerr << "Error : IKinectSensor::Open()" << std::endl;
  return -1;
}
リスト1.1 図1の「Sensor」に該当する部分
  • 1Kinect v2を扱うためのSensorインターフェース。
  • 2デフォルトのSensorを取得する。
  • 3Sensorを開く。

「Source」

 SensorからSourceを取得する。

C++
// Source
IColorFrameSource* pColorSource;  //……1
hResult = pSensor->get_ColorFrameSource( &pColorSource );  //……2
if( FAILED( hResult ) ){
  std::cerr << "Error : IKinectSensor::get_ColorFrameSource()" << std::endl;
  return -1;
}
リスト1.2 図1の「Source」に該当する部分
  • 1ColorフレームのためのSourceインターフェース。
  • 2SensorからSourceを取得する。

「Reader」

 SourceからReaderを開く。

C++
// Reader
IColorFrameReader* pColorReader;  //……1
hResult = pColorSource->OpenReader( &pColorReader );  //……2
if( FAILED( hResult ) ){
  std::cerr << "Error : IColorFrameSource::OpenReader()" << std::endl;
  return -1;
}
リスト1.3 図1の「Reader」に該当する部分
  • 1ColorフレームのためのReaderインターフェース。
  • 2SourceからReaderを開く。

「Frame」~「Data」

 Readerから最新のFrameを取得する。

C++
int width = 1920;   //……1
int height = 1080;  //……1
unsigned int bufferSize = width * height * 4 * sizeof( unsigned char );  //……2
cv::Mat bufferMat( height, width, CV_8UC4 );  //……3
cv::Mat colorMat( height / 2, width / 2, CV_8UC4 );  //……3
cv::namedWindow( "Color" );

while( 1 ){
  // Frame
  IColorFrame* pColorFrame=nullptr;  //……4
  hResult=pColorReader->AcquireLatestFrame( &pColorFrame );  //……5
  if( SUCCEEDED( hResult ) ){
    hResult = pColorFrame->CopyConvertedFrameDataToArray( bufferSize, reinterpret_cast<BYTE*>( bufferMat.data ), ColorImageFormat_Bgra );  //……6
    if( SUCCEEDED( hResult ) ){
      cv::resize( bufferMat, colorMat, cv::Size(), 0.5, 0.5 );   //……7
    }
  }
  SafeRelease( pColorFrame );   //……8

  // Show Window
  cv::imshow( "Color", colorMat );
  if( cv::waitKey( 30 ) == VK_ESCAPE ){
    break;
  }
}
リスト1.4 図1の「Frame」、「Data」に該当する部分
  • 1Color画像のサイズ(1920×1080)。
    ここでは説明の簡素化のため画像サイズを決め打ちしているが、サンプルプログラムではSourceからフレーム情報を取得している。
  • 2Color画像のデータサイズ。
  • 3Color画像を扱うためにOpenCVのcv::Mat型を準備する。
    「bufferMat」は生の画像データ、「colorMat」はリサイズした画像データを扱う。
    「CV_8UC4」は、符号無し8bit整数(8U)が4channel(C4)並んで1画素を表現するデータ形式。
  • 4Color画像を取得するためのFrameインターフェース。
  • 5Readerから最新のFrameを取得する。
  • 6FrameからColor画像を取得する。
    デフォルトのフォーマットはYUY2(=輝度と色差で表現するフォーマット)だが、扱いやすいBGRAに変換して取得する。
  • 7縦横それぞれ半分のサイズ(960×540)に縮小する。
  • 8Frameを解放する。
    内部バッファが解放されて次のデータを取得できる状態になる。

 Frameが取得できたらColor画像のデータを取り出し表示する。Kinect SDK v1では画像サイズやフォーマットをあらかじめ指定していたが、Kinect SDK v2では画像サイズを指定することはできない。そのため、データを取得してから任意の形に整える。

 取得したColor画像はそのまま表示するにはサイズ(1920×1080)が大きいため、ここではOpenCVのリサイズ命令(cv::resize())を用いて縦横それぞれ半分のサイズ(960×540)に縮小している。

 取り出したColor画像のデータはBGRAのフォーマットを指定した場合、図2のように並んでいる。青(B)、緑(G)、赤(R)、無効値(A)の合計32bitで1画素を構成している。

図2 Color画像のデータの並び

実行結果

 このサンプルプログラムを実行すると図3のようにKinect v2から取得したColor画像が表示される。

図3 実行結果

まとめ

 今回はKinect SDK v2のデータを取得する基本的な流れとColor画像を取得するサンプルプログラムを紹介した。次回はDepthデータを取得するサンプルプログラムを紹介する。

※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

1. Kinect v1とKinect v2の徹底比較

Kinect for Windowsの旧版と、次世代型の新版を比較しながら、進化したハードウェア&ソフトウェアをC++開発者向けに紹介する(正式版に対応させた改訂連載スタート)。今回はセンサー仕様や動作要件を徹底的に比較する。

2. 【現在、表示中】≫ Kinect v2プログラミング(C++) - Color編

Kinect SDK v2で、データを取得する基本的な流れを説明。Color画像を取得するサンプルプログラムを紹介する。正式版に合わせて改訂。

3. Kinect v2プログラミング(C++) - Depth編

Kinect SDK v2プレビュー版で、Depthデータを取得する方法を説明する(改訂版)。

4. Kinect v2プログラミング(C++) - BodyIndex編

Kinect SDK v2で、BodyIndex(人物領域)を取得する方法を、サンプルコードを示しながら説明する(正式版に合わせて改訂)。

5. Kinect v2プログラミング(C++) - Body編

Kinect SDK v2に実装されている主要な機能の紹介は、一通り完了。今回は、Body(人物姿勢)を取得する方法を説明する(正式版に合わせて改訂)。

イベント情報(メディアスポンサーです)

サイトからのお知らせ

Twitterでつぶやこう!