このエントリはKINECT SDK Advent Calendar 2011 : ATNDの12月5日分です!!
Advent Calendarでの、僕の全プロジェクトはこちらです
前回までで、RGBカメラのデータを扱ったので、今回はKINECTの特長の一つである距離カメラを使ってみます。
距離データからこんな画像を表示してみましょう。
見た目の解説
前回同様、Imageを一つはっつけてます
<Window x:Class="DepthWPF.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="521" Width="663"> <Grid> <Image Height="480" HorizontalAlignment="Left" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="640 " /> </Grid> </Window>
中身の解説
using System; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; using Microsoft.Research.Kinect.Nui; namespace DepthWPF { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // Depthのみを使う設定で初期化 Runtime kinect = Runtime.Kinects[0]; kinect.Initialize( RuntimeOptions.UseDepth ); kinect.DepthStream.Open( ImageStreamType.Depth, 2, ImageResolution.Resolution640x480, ImageType.Depth ); kinect.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>( kinect_DepthFrameReady ); } void kinect_DepthFrameReady( object sender, ImageFrameReadyEventArgs e ) { var source = e.ImageFrame.Image; image1.Source = BitmapSource.Create( source.Width, source.Height, 96, 96, PixelFormats.Gray16, null, ConvertGrayScale( source ).Bits, source.Width * source.BytesPerPixel ); } // 距離データをグレースケールに変換する private static PlanarImage ConvertGrayScale( PlanarImage source ) { // thanks : http://www.atmarkit.co.jp/fdotnet/kinectsdkbeta/kinectsdkbeta02/kinectsdkbeta02_02.html for ( int i = 0; i < source.Bits.Length; i += 2 ) { // Depthのみ(ユーザーデータなし)のデータ取得 ushort depth = (ushort)(source.Bits[i] | (source.Bits[i+1] << 8)); // 0x0fff(Depthの最大値)を0-0xffffの間に変換する depth = (ushort)(0xffff - (0xffff * depth / 0x0fff)); // 戻す source.Bits[i] = (byte)(depth & 0xff); source.Bits[i+1] = (byte)((depth >> 8) & 0xff); } return source; } } }
初期化
Depthのみを使う設定で初期化します。
- Runtime.InitializeでRuntimeOptions.UseDepthを設定
- Runtime.DepthStream.OpenでImageStreamType.Depthを設定。DepthのみなのでResolutionは640x480を指定(ユーザーデータが入ると320x240になる)
- Runtime.DepthFrameReady でデータ更新イベントを設定
// Depthのみを使う設定で初期化 Runtime kinect = Runtime.Kinects[0]; kinect.Initialize( RuntimeOptions.UseDepth ); kinect.DepthStream.Open( ImageStreamType.Depth, 2, ImageResolution.Resolution640x480, ImageType.Depth ); kinect.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>( kinect_DepthFrameReady );
データの更新
RGBカメラと同様です。距離データをグレースケールに変換するために、ビット列をConvertGrayScaleメソッドに通しています。
void kinect_DepthFrameReady( object sender, ImageFrameReadyEventArgs e ) { var source = e.ImageFrame.Image; image1.Source = BitmapSource.Create( source.Width, source.Height, 96, 96, PixelFormats.Gray16, null, ConvertGrayScale( source ).Bits, source.Width * source.BytesPerPixel ); }
グレースケールへの変換
距離データを16bitのグレースケールに変換します。
変換はこちらを参考にしました。ただし、16bitの最大値なので、0-0xffff の間に設定しています
// 距離データをグレースケールに変換する private static PlanarImage ConvertGrayScale( PlanarImage source ) { for ( int i = 0; i < source.Bits.Length; i += 2 ) { // Depthのみ(ユーザーデータなし)のデータ取得 ushort depth = (ushort)(source.Bits[i] | (source.Bits[i+1] << 8)); // 0x0fff(Depthの最大値)を0-0xffffの間に変換する depth = (ushort)(0xffff - (0xffff * depth / 0x0fff)); // 戻す source.Bits[i] = (byte)(depth & 0xff); source.Bits[i+1] = (byte)((depth >> 8) & 0xff); } return source; }
まとめ
このように簡単に距離データを扱うことができます。
距離そのものを扱う場合には
ushort depth = (ushort)(source.Bits[i] | (source.Bits[i+1] << 8));
のdepthを使えばOKです