ブログ@kaorun55

HoloLensやKinectなどのDepthセンサーを中心に書いています。

Kinect for Windows SDK v2.0 で音の方向にいる人を識別する

Kinect for Windows SDK v2.0入門 目次

ここでは「音の方向にいる人」の取得について解説します。v1ではこのようなAPIはなかったので、音の方向の角度と、人の位置から自分で計算する必要がありました。v2ではビーム方向の人のTrackingId(BodyのTrackingIdと同一)が取得できるので、簡単に音の方向の人がわかります。また、BodyIndexも人を検出したピクセルが0-5、それ以外が255(byte/pixelなので)となり、BodyIndexがまさにBodyのインデックスになっているようです(v1では人を検出したピクセルが1-6、それ以外が0となっていました)。

これを利用して、ビーム方向の人(TrackingId)をBodyと関連付け、BodyIndexと関連付けるところまでをやってみます。

環境

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

実行結果

まず、Kinectに認識された人のシルエット(赤)が表示されます。Kinectに認識された人が音を出すと、その人の色が青に変わります。

スクリーンショット 2014-08-08 11.14.43スクリーンショット 2014-08-08 11.14.50

何人かでやると、こんな感じになります。

解説

ビーム方向のTrackingIdをBodyIndexにマップするため、以下の手順を行います。

  • AudioSourceでビーム方向と、そのTrackingIdを取得する。
  • BodyFrameSourceで取得したBodyのTrackingIdとビーム方向のTrackingIdを比較し、そのBodyのインデックス(BodyIndex)を取得する。
  • BodyIndexFrameSourceで取得したインデックスとビーム方向のTrackingIdのインデックスを比較し、そのインデックスの人を見つける。

とういうわけで、今回はAudioSource、BodyFrameSource、BodyIndexFrameSourceの3つを使います。初期化はそれぞれのFrameReader開き、データを取得するだけなので割愛します。ソースを見てください。データの取得のほうを解説します。

データの取得

データのマッピングについては上記の3手順で行います。

ビーム方向のTrackingIdを取得する

ここで新しく出てくるものは、ビーム方向の人のTrackingIdの取得方法です。ビーム方向の人はAudioBeamSubFrame.AudioBodyCorrelationsにあり、これはリストになっています。が、現状では1人しか認識しません。AudioBodyCorrelationsに何かしら入っていれば(人を認識していれば)、最初のAudioBodyCorrelationsのTrackingIdを取得しておきます。 

C++

void updateAudioFrame()

{

ComPtr<IAudioBeamFrameList> audioBeamFrameList;

auto ret = audioBeamFrameReader->AcquireLatestBeamFrames( &audioBeamFrameList );

if ( ret != S_OK ){

return;

}

ComPtr<IAudioBeamFrame> audioBeamFrame;

ERROR_CHECK( audioBeamFrameList->OpenAudioBeamFrame( 0, &audioBeamFrame ) );

ComPtr<IAudioBeamSubFrame> audioBeamSubFrame;

ERROR_CHECK( audioBeamFrame->GetSubFrame( 0, &audioBeamSubFrame ) );

// 角度および角度の信頼性を取得する

ERROR_CHECK( audioBeamSubFrame->get_BeamAngle( &beamAngle ) );

// ビーム方向にいる人の数を取得する

UINT32 count = 0;

ERROR_CHECK( audioBeamSubFrame->get_AudioBodyCorrelationCount( &count ) );

if ( count == 0 ){

audioTrackingId = (UINT64)-1;

return;

}

// ビーム方向の人のTrackingIdを取得する

ComPtr<IAudioBodyCorrelation> audioBodyCorrelation;

ERROR_CHECK( audioBeamSubFrame->GetAudioBodyCorrelation( 0, &audioBodyCorrelation ) );

ERROR_CHECK( audioBodyCorrelation->get_BodyTrackingId( &audioTrackingId ) );

}

C#(デスクトップ)

void audioBeamFrameReader_FrameArrived( object sender, AudioBeamFrameArrivedEventArgs e )

{

using ( var audioFrames = e.FrameReference.AcquireBeamFrames() ) {

if ( audioFrames == null ) {

return;

}

var subFrame = audioFrames[0].SubFrames[0];

// 音の方向

LineBeamAngle.Angle = (int)(subFrame.BeamAngle * 180 / Math.PI);

// ビーム角度、信頼性、ビーム方向のBody数を表示

Text1.Text = (subFrame.BeamAngle * 180.0f / (float)Math.PI).ToString();

Text2.Text = subFrame.BeamAngleConfidence.ToString();

Text3.Text = subFrame.AudioBodyCorrelations.Count.ToString();

// ビーム方向に人がいれば、そのTrackibngIdを保存する

if ( subFrame.AudioBodyCorrelations.Count != 0 ) {

AudioTrackingId = subFrame.AudioBodyCorrelations[0].BodyTrackingId;

}

else {

AudioTrackingId = ulong.MaxValue;

}

}

}

C#(Windows ストアアプリ)

なし

ビーム方向のTrackingIdからBodyIndexを取得する

続いてビーム方向のTrackingIdからBodyIndexを取得します。Bodyを使って、TrackingIdからBodyIndexを取得します。ビーム方向のTrackingIdをBodyのTrackingIdと比較し、一致したBodyIndexを保持しておきます。これをBodyIndexの表示で利用します。

C++

void draw()

{

...

// ビーム方向の人のインデックスを探す

audioTrackingIndex = -1;

if ( audioTrackingId != (UINT64)-1 ){

for ( int i = 0; i < 6; ++i ){

UINT64 trackingId = 0;

bodies[i]->get_TrackingId( &trackingId );

if ( trackingId == audioTrackingId ){

audioTrackingIndex = i;

break;

}

}

}

...

}

C#(デスクトップ)

void bodyFrameReader_FrameArrived( object sender, BodyFrameArrivedEventArgs e )

{

// ボディデータを取得する

using ( var bodyFrame = e.FrameReference.AcquireFrame() ) {

if ( bodyFrame == null ) {

return;

}

bodyFrame.GetAndRefreshBodyData( bodies );

}

// ビーム方向と一致するTrackingIdがあれば、そのインデックス(BodyIndex)を保存する

AudioTrackingIndex = -1;

for ( int i = 0; i < bodies.Length; i++ ) {

if ( bodies[i].TrackingId == AudioTrackingId ) {

AudioTrackingIndex = i;

break;

}

}

}

C#(Windows ストアアプリ)

なし

BodyIndexの人に色付けする

最後にBodyIndexの人に色付けします。上で取得したBodyIndexの人のピクセルを判定します。

C++

void draw()

{

...

// ビーム方向の人に色付けする

for ( int i = 0; i < BodyIndexWidth * BodyIndexHeight; ++i ){

int index = i * 4;

// 人がいれば255以外

if ( bodyIndexBuffer[i] != 255 ){

if ( bodyIndexBuffer[i] == audioTrackingIndex ){

image.data[index + 0] = 255;

image.data[index + 1] = 0;

image.data[index + 2] = 0;

}

else {

image.data[index + 0] = 0;

image.data[index + 1] = 0;

image.data[index + 2] = 255;

}

}

else{

image.data[index + 0] = 255;

image.data[index + 1] = 255;

image.data[index + 2] = 255;

}

}

...

}

C#(デスクトップ)

void bodyIndexFrameReader_FrameArrived( object sender, BodyIndexFrameArrivedEventArgs e )

{

// ボディインデックスデータを取得する

using ( var bodyIndexFrame = e.FrameReference.AcquireFrame() ) {

if ( bodyIndexFrame == null ) {

return;

}

bodyIndexFrame.CopyFrameDataToArray( bodyIndexBuffer );

}

// ボディインデックスデータをBGRAデータに変換する

for ( int i = 0; i < bodyIndexBuffer.Length; i++ ) {

var index = bodyIndexBuffer[i];

var colorIndex = i * 4;

if ( index != 255 ) {

// BodyIndexがビーム方向のTrackingIdのインデックスと一致していたら、その人が音を出している

if ( index == AudioTrackingIndex ) {

bodyIndexColorBuffer[colorIndex + 0] = 255;

bodyIndexColorBuffer[colorIndex + 1] = 0;

bodyIndexColorBuffer[colorIndex + 2] = 0;

bodyIndexColorBuffer[colorIndex + 3] = 255;

}

else {

bodyIndexColorBuffer[colorIndex + 0] = 0;

bodyIndexColorBuffer[colorIndex + 1] = 0;

bodyIndexColorBuffer[colorIndex + 2] = 255;

bodyIndexColorBuffer[colorIndex + 3] = 255;

}

}

else {

bodyIndexColorBuffer[colorIndex + 0] = 255;

bodyIndexColorBuffer[colorIndex + 1] = 255;

bodyIndexColorBuffer[colorIndex + 2] = 255;

bodyIndexColorBuffer[colorIndex + 3] = 255;

}

}

// ビットマップにする

bodyIndexColorImage.WritePixels( bodyIndexColorRect, bodyIndexColorBuffer, bodyIndexColorStride, 0 );

}

C#(Windows ストアアプリ)

なし

まとめ

このように簡単にビーム方向の人の認識ができます。v1では人と音をコラボレーションしたものは、ほとんど見なかったのですが、v2ではたくさん出てくるといいですねぇ。

Kinect for Windows SDK v2.0入門 目次