ブログ@kaorun55

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

Kinect for Windows SDK v1.7 の Interactionを使ってみる(C#)

インタラクションライブラリを使ってみます。まずはデータを可視化するところから。

プロジェクトの準備として、いくつかのライブラリを設定します。Kinect SDK自体の設定も必要ですが、ここでは割愛します。

次の2つのライブラリをプロジェクトに追加し、コンテンツとして実行ファイルの場所にコピーさせます。

  • C:\Program Files\Microsoft SDKs\Kinect\Developer Toolkit v1.7.0\Redist\amd64\KinectInteraction170_64.dll
  • C:\Program Files\Microsoft SDKs\Kinect\Developer Toolkit v1.7.0\Redist\x86\KinectInteraction170_32.dll

次のライブラリを参照設定に追加します。

コード

XAML

データを表示するDataGridとRGBカメラのImageを追加します。

<Window x:Class="_01_KinectInteractionCS.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="MainWindow" Width="1200" SizeToContent="Height">

<StackPanel Orientation="Vertical">

<DataGrid x:Name="Grid" Height="90" FontSize="16"

AutoGeneratingColumn="Grid_AutoGeneratingColumn" />

<Image x:Name="ImageRgb" Width="640" Height="480"/>

</StackPanel>

</Window>

コードビハインド

インタラクションの検出にはInteractionStreamを使用します。インスタンス生成時にKinectSensorとIInteractionClientの派生クラスが必要になります。IInteractionClientはその座標地点での認識状態を返すメソッドを持っており、ここれはKinectAdapterとしてあります。

次にインタラクションが更新されたときに呼ばれるイベントを登録します。

// インタラクションライブラリの初期化

stream = new InteractionStream( kinect, new KinectAdapter() );

stream.InteractionFrameReady += stream_InteractionFrameReady;

次にKinectのデータ更新ごとにDepthおよびSkeletonをライブラリに渡します。なおDepthは拡張データのほうを渡しますが、ライブラリでGetRawPixelData()という拡張メソッドが定義されています。残念ながらSkeletonは従来通りです。

void kinect_AllFramesReady( object sender, AllFramesReadyEventArgs e )

{

using ( var colorFrame = e.OpenColorImageFrame() ) {

if ( colorFrame != null ) {

var pixel = new byte[colorFrame.PixelDataLength];

colorFrame.CopyPixelDataTo( pixel );

ImageRgb.Source = BitmapSource.Create( colorFrame.Width, colorFrame.Height, 96, 96,

PixelFormats.Bgr32, null, pixel, colorFrame.Width * 4 );

}

}

using ( var depthFrame = e.OpenDepthImageFrame() ) {

if ( depthFrame != null ) {

// Depth情報を入れる

// GetRawPixelData()はインタラクションライブラリ内で実装された拡張メソッド

stream.ProcessDepth( depthFrame.GetRawPixelData(), depthFrame.Timestamp );

}

}

using ( var skeletonFrame = e.OpenSkeletonFrame() ) {

if ( skeletonFrame != null ) {

var skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];

skeletonFrame.CopySkeletonDataTo( skeletons );

// スケルトン情報を入れる

stream.ProcessSkeleton( skeletons, kinect.AccelerometerGetCurrentReading(), skeletonFrame.Timestamp );

}

}

}

インタラクションデータが更新されると、最初に登録したイベントハンドラが呼ばれます。 ここですべてのユーザーの左右の手の情報が入っているので、データを表示させます。

座標データは詳しい説明がないため、今のところどのような形かはよくわかっていません。サンプルの通りの変換をしても意図したものと違う感じです。

void stream_InteractionFrameReady( object sender, InteractionFrameReadyEventArgs e )

{

using ( var interactionFrame = e.OpenInteractionFrame() ) {

if ( interactionFrame != null ) {

var userInfos = new UserInfo[InteractionFrame.UserInfoArrayLength];

interactionFrame.CopyInteractionDataTo( userInfos );

List<InteractionHandPointer> hands = new List<InteractionHandPointer>();

foreach ( var user in userInfos ) {

if ( user.SkeletonTrackingId != 0 ) {

foreach ( var hand in user.HandPointers ) {

hands.Add( hand );

}

}

}

Grid.ItemsSource = hands;

}

}

}

すべてのコードはこのようになっています。

using System.Collections.Generic;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using Microsoft.Kinect;

using Microsoft.Kinect.Toolkit.Interaction;

namespace _01_KinectInteractionCS

{

/// <summary>

/// MainWindow.xaml の相互作用ロジック

/// </summary>

public partial class MainWindow : Window

{

KinectSensor kinect;

InteractionStream stream;

// 検出するデータを返す

public class KinectAdapter : IInteractionClient

{

public InteractionInfo GetInteractionInfoAtLocation( int skeletonTrackingId,

InteractionHandType handType, double x, double y )

{

return new InteractionInfo()

{

IsGripTarget = true,

};

}

}

public MainWindow()

{

InitializeComponent();

Loaded += MainWindow_Loaded;

}

void MainWindow_Loaded( object sender, RoutedEventArgs e )

{

// Kinectの初期化

kinect = KinectSensor.KinectSensors[0];

kinect.AllFramesReady += kinect_AllFramesReady;

kinect.ColorStream.Enable();

kinect.DepthStream.Enable();

kinect.SkeletonStream.Enable();

kinect.Start();

// インタラクションライブラリの初期化

stream = new InteractionStream( kinect, new KinectAdapter() );

stream.InteractionFrameReady += stream_InteractionFrameReady;

}

void kinect_AllFramesReady( object sender, AllFramesReadyEventArgs e )

{

using ( var colorFrame = e.OpenColorImageFrame() ) {

if ( colorFrame != null ) {

var pixel = new byte[colorFrame.PixelDataLength];

colorFrame.CopyPixelDataTo( pixel );

ImageRgb.Source = BitmapSource.Create( colorFrame.Width, colorFrame.Height,

96, 96, PixelFormats.Bgr32, null, pixel, colorFrame.Width * 4 );

}

}

using ( var depthFrame = e.OpenDepthImageFrame() ) {

if ( depthFrame != null ) {

// Depth情報を入れる

// GetRawPixelData()はインタラクションライブラリ内で実装された拡張メソッド

stream.ProcessDepth( depthFrame.GetRawPixelData(), depthFrame.Timestamp );

}

}

using ( var skeletonFrame = e.OpenSkeletonFrame() ) {

if ( skeletonFrame != null ) {

var skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];

skeletonFrame.CopySkeletonDataTo( skeletons );

// スケルトン情報を入れる

stream.ProcessSkeleton( skeletons, kinect.AccelerometerGetCurrentReading(),

skeletonFrame.Timestamp );

}

}

}

void stream_InteractionFrameReady( object sender, InteractionFrameReadyEventArgs e )

{

using ( var interactionFrame = e.OpenInteractionFrame() ) {

if ( interactionFrame != null ) {

var userInfos = new UserInfo[InteractionFrame.UserInfoArrayLength];

interactionFrame.CopyInteractionDataTo( userInfos );

List<InteractionHandPointer> hands = new List<InteractionHandPointer>();

foreach ( var user in userInfos ) {

if ( user.SkeletonTrackingId != 0 ) {

foreach ( var hand in user.HandPointers ) {

hands.Add( hand );

}

}

}

Grid.ItemsSource = hands;

}

}

}

private void Grid_AutoGeneratingColumn( object sender,

DataGridAutoGeneratingColumnEventArgs e )

{

if ( e.PropertyType == typeof( double ) ) {

DataGridTextColumn dataGridTextColumn = e.Column as DataGridTextColumn;

if ( dataGridTextColumn != null ) {

dataGridTextColumn.Binding.StringFormat = "{0:f3}";

}

}

}

}

}