ブログ@kaorun55

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

Kinect for Windows SDK v1.6 で拡張された距離データを取得する(C#)

続いて拡張された距離データを取得してみます。v1.5までの距離データは、1ピクセルあたり16bitのうち、上位13bitを距離データ、下位3bitをプレイヤーインデックスとして利用していました。13bitの距離データも、最上位ビットは使用しないため、実際には12bitのデータであるため、4096までのデータしか取得することができませんでした。

v1.6では新たにDepthImagePixelとして、16bitの距離データとプレイヤーインデックスを持つ構造体が定義され、DepthImageFrame.CopyDepthImagePixelDataTo()で全体の距離データを取得することができるようになりました。これによって4000mm(4m)以上の距離データを取得できるようになりました。ただし、通常の範囲外の距離データについては、範囲内のデータ(800-4000mm)に比べて精度が低くなるようです。

DepthImagePixelコード上の定義は次のようになっています。

コード上でもそれほど変わらず、従来はshortの配列に対してDepthImageFrame.CopyPixelDataTo()で取得していた部分を、DepthImagePixelの配列に対してDepthImageFrame.CopyDepthImagePixelDataTo()で取得するようになっています。DepthImagePixelではDepthとPlayerがそれぞれ定義されているため、v1.5までのようにビットシフトする必要もなくなりました。ここでは中心点の距離を表示しています。

全体のコードはこちらにあります。

void kinect_DepthFrameReady( object sender, DepthImageFrameReadyEventArgs e )

{

using ( DepthImageFrame frame = e.OpenDepthImageFrame() ) {

if ( frame == null ) {

return;

}

// DepthImagePixel で取得すると、16bitの距離データ+プライヤーインデックス

// が取得できる

DepthImagePixel[] depth = new DepthImagePixel[frame.PixelDataLength];

frame.CopyDepthImagePixelDataTo( depth );

// 中心点の距離を表示する

int index = (frame.Height / 2) * frame.Width + (frame.Width / 2);

textDepth.Text = string.Format( "{0}mm", depth[index].Depth );

// 可視画像に変換する(14bitで16m)

// どこまでいけるかは不明だけどOpenNI時の10m弱くらいが限界?

short[] pixel = new short[frame.PixelDataLength];

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

pixel[i] = (short)~(depth[i].Depth * 0xFFFF / 0x3FFF);

}

imageDepth.Source = BitmapSource.Create( frame.Width, frame.Height, 96, 96,

PixelFormats.Gray16, null, pixel, frame.Width * frame.BytesPerPixel );

}

}

上限および下限値はDepthImageStream.MinDepthおよびDepthImageStream.MaxDepthに定義されていますが、v1.5までと値が変わらないため正確な値は不明です。実測したところでは大体次のようになっています(OpenNIでKinectを利用していた時の値と大体同じです)。

  • Defaultモード:490mm-9300mm
  • Nearモード:450mm-8300mm

なお、プレイヤーおよびスケルトンの追跡は、拡張された距離データは適用されず、従来通り0.8m-4mまたは0.4m-3mになるようです。