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と関連付けるところまでをやってみます。
環境
筆者の環境は次の通りです。
- Windows 8.1 Pro Update1 64bit
- Visual Studio 2013 Ultimate(Express for Windows Desktopでも可)
- Kinect for Windows SDK v2.0-1409(リリース版)
- 32bitアプリケーション
- サンプルコードのリポジトリ
実行結果
まず、Kinectに認識された人のシルエット(赤)が表示されます。Kinectに認識された人が音を出すと、その人の色が青に変わります。
何人かでやると、こんな感じになります。
解説
ビーム方向の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ではたくさん出てくるといいですねぇ。