センサーの範囲内にいる人間を見つけて撮影・保存するKinectサンプル
ウィンドウ(WPF)の追加(DataShowWindow.xaml)
保存した画像の一覧を表示させるために、DataShowWindow.xamlを作成します。VS2010メニューの「プロジェクト(P)/新しい項目の追加(W)」と選択して、「インストールされたテンプレート」から「WPF」を選択します。
右側に表示される項目から「ウィンドウ(WPF)」を選択し、「名前(N)」に「DataShowWindow.xaml」と指定します(図5)。
コントロールの配置
DataShowWindow.xamlのデザイン画面上にListBoxコントロールを1個配置します(図6)。書き出されるXAMLコードをリスト2のように編集します。
リスト2 書き出され編集されたXAMLコード(DataShowWindow.xaml)
- (1)
プロパティ要素内にKeyがListBoxTemplateという名前の 要素を配置します。その中に 要素を配置し、Marginプロパティに10を指定して、余白を設けます。 要素内にTextBlockを1個配置し、TextプロパティにOutRoomTimeプロパティをバインドしておきます。またImageを1個配置しSourceプロパティにImageNameプロパティをバインドしておきます。これらの名前はVBコード内で定義したプロパティ名です。 - (2)ListBoxコントロールのItemTemplateで(1)で定義したListBoxTemplateを参照します。
<Window x:Class="DataShowWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="DataShowWindow" Height="777" Width="489"> <Window.Resources> ■(1) <DataTemplate x:Key="ListBoxTemplate"> <StackPanel Margin="10"> <TextBlock Text="{Binding OutRoomTime}" FontSize="20" /> ■(1) <Image Width="358" Height="269" Source="{Binding ImageName}"/> ■(1) </StackPanel> </DataTemplate> </Window.Resources> ■(1) <Grid Height="751" Width="482"> <ListBox Height="716" HorizontalAlignment="Left" Margin="15,12,0,0" Name="ListBox1" VerticalAlignment="Top" Width="441" ItemTemplate="{StaticResource ListBoxTemplate}"/> ■(2) <Button Content="データ全削除" Height="50" HorizontalAlignment="Left" Margin="12,14,0,0" Name="Button1" VerticalAlignment="Top" Width="443" FontSize="22" FontWeight="Bold" Visibility="Collapsed" /> </Grid> </Window>
次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト3のコードを記述します。
ロジックコードを記述する
リスト3 (MainWindow.xaml.vb)
Option Strict On Imports Microsoft.Kinect Imports Coding4Fun.Kinect.Wpf
タイマーを使用するためSystem.Windows.Threading名前空間をインポートします。
Imports System.Windows.Threading Imports System.IO Class MainWindow
一個のKinectセンサーを表すメンバ変数kinectを宣言します。
Dim kinect As KinectSensor
Kinectセンサーの視界内に人がいるかどうかを判別するブール型のメンバ変数flagを宣言し、Falseで初期化しておきます。
Dim flag As Boolean = False
Kinectセンサーの視界から離れた時間と、視界に入った時間を保持するメンバ変数を宣言します。
Dim outTime As String = String.Empty Dim inTime As String
指定した時間の間隔で、指定した優先順位で処理されるタイマークラスのメンバ変数myTimerを宣言します。
Dim myTimer As DispatcherTimer Dim imageFileName As String
ウィンドウが読み込まれた時の処理
システムの特別なフォルダである、「マイピクチャ」フォルダへのディレクトリパスを取得して、変数dirに格納しておきます。「マイピクチャ」フォルダ内にKINECTというサブフォルダが存在していなかった場合は、CreateDirectoryメソッドで「マイピクチャ」内にKINECTというフォルダを作成します。
KINECTフォルダへのディレクトリパスを変数fileDirに格納します。KINECTフォルダ内にImageFileList.xmlというファイルが存在する場合、つまり、画像が保存されている場合は、[データ表示]ボタンの使用を可能にします。それ以外は、使用を不可とします。
新しいタイマーのインスタンスを作成し、Intervalプロパティに1000ミリセコンド(1秒)を指定します。
AddHandlerステートメントで、指定したタイマーの間隔が経過し、タイマーが有効である場合に発生するTickイベントに、イベントハンドラを指定します。イベントハンドラ内では、非表示にしているinTextBlock内に現在の年月日時分秒を表示しておきます(ただし非表示)。タイマーをスタートします。
Kinectセンサーを取得しRGBカメラを有効にします。またスケルトンも有効にし、RGBカメラ、スケルトンのフレームが更新された時に発生する、AllFramesReadyイベントにkinect_AllFramesReadyイベントハンドラを指定します。Kinectセンサーを動作させます。
Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded Dim dir As String= Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) If Directory.Exists(Path.Combine(dir, "KINECT")) = False Then Directory.CreateDirectory(Path.Combine(dir, "KINECT")) End If Dim fileDir = Path.Combine(dir, "KINECT") If File.Exists(Path.Combine(fileDir, "ImageFileList.xml")) = True Then Button1.IsEnabled = True Else Button1.IsEnabled = False End If myTimer = New DispatcherTimer myTimer.Interval = New TimeSpan(1000) AddHandler myTimer.Tick, Sub(timerSender As Object, timerArgs As EventArgs) inTextBlock.Text = DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") End Sub myTimer.Start() If KinectSensor.KinectSensors.Count = 0 Then MessageBox.Show("KINECTが接続されておりません。") Exit Sub Else kinect = KinectSensor.KinectSensors(0) kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30) kinect.SkeletonStream.Enable() AddHandler kinect.AllFramesReady, AddressOf kinect_AllFramesReady kinect.Start() End If End Sub
RGBカメラ、距離カメラ、スケルトンのフレームが更新された時に発生するイベント
Image1という名前を持つImageコントロールのSourceプロパティに、e.OpenColorImageFrameメソッドで、新しいフレームのRGBカメラの情報を取得し、Coding4Fun.Kinect.Wpfの拡張メソッドであるToBitmapSourceで、myImageをBitmapSourceに変換して指定します。これで、Imageコントロール内にカラーの実画像(実写)が表示されます。
このメソッドで取得するColorImageFrameは、Usingで括るか、明示的にDisposeする必要があります。
非表示になっているTextBlock2内にFalseと表示します(ただし非表示)。メンバ変数flagがTrueの場合、つまりKinectセンサーの視界内に人がいる場合は、タイマーを停止し、ListBox内をクリアして、現在の年月日時分秒を追加します。ListBox1.SelectedIndex = 0で、その項目を選択された状態にしておきます。
DataSaveプロシージャを実行します。メンバ変数flagがFalseの場合、つまりKinectセンサーの視界から人がいなくなった場合は、タイマーを再開します。スケルトンを追跡するmySkeletonShowプロシージャを実行します。「マイピクチャ」のKINECTフォルダには1秒ごとの画像データが保存されますので、ストレージを圧迫しないようこまめに削除してお試しください。
Private Sub kinect_AllFramesReady(sender As Object, e As AllFramesReadyEventArgs) Using myImage As ColorImageFrame = e.OpenColorImageFrame Image1.Source = myImage.ToBitmapSource End Using TextBlock2.Text = flag.ToString If flag = True Then myTimer.Stop() ListBox1.Items.Clear() ListBox1.Items.Add(DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒")) ListBox1.SelectedIndex = 0 DataSave() Else TextBlock1.Text = String.Empty myTimer.Start() End If mySkeletonShow(e) End Sub
スケルトンを追跡し、Kinectセンサーの視界に人がいるかどうかを判別する処理
e.OpenSkeletonFrameメソッドでスケルトンフレームを開き、スケルトンのフレームを取得します。スケルトンのフレームが取得できた時の処理を行います。
スケルトンのデータを保持するのに必要なメモリを確保するために、mySkeletonFrame.SkeletonArrayLength-1で初期化された新しいSkeletonのインスタンス、skeletonData配列オブジェクトを作成します。skeletonArrayLengthプロパティは、スケルトン配列の長さを取得します。これで、スケルトンデータのバイト列を確保し、CopySkeletonDataToメソッドで、スケルトンフレームからスケルトンのデータを取り出します。
取得されるデータは人の分取得されますので、それぞれのトラッキング状態を確認します。CopySkeletonDataToメソッドは、指定した配列、この場合skeletonData配列変数に、現在のスケルトンフレーム、この場合mySkeletonFrameオブジェクトをコピーするメソッドです。
変数mySkeletonでスケルトンフレームデータの中を反復処理しながら、スケルトンがトラッキング(追跡)されている場合は、メンバ変数flagをTrueで初期化しタイマーを停止します。
スケルトンのフレームが取得できなかった場合は、メンバ変数flagをFalseで初期化し、タイマーを開始します。
Private Sub mySkeletonShow(e As AllFramesReadyEventArgs) Dim mySkeletonFrame As SkeletonFrame = e.OpenSkeletonFrame If mySkeletonFrame Is Nothing = False Then Dim skeletonData As Skeleton() = New Skeleton(mySkeletonFrame.SkeletonArrayLength - 1) {} mySkeletonFrame.CopySkeletonDataTo(skeletonData) For Each mySkeleton In skeletonData If mySkeleton.TrackingState = SkeletonTrackingState.Tracked Then flag = True myTimer.Stop() End If Next Else flag = False myTimer.Start() End If End Sub
センサーの範囲内にいる人間を見つけて撮影・保存するKinectサンプル
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Windows Phoneで自宅の様子をリモート監視するKinectプログラムを作ってみる
- タッチパネルでドラッグ&ドロップを使う汎用的なサンプル
- カメラで写した写真を分離ストレージに保存し、写真の一覧を表示する
- 撮影した写真を分離ストレージとPicturesHUBに保存する
- 写真をハート型に切り抜いて撮影するサンプル
- 声で選んだアイテムをプレイヤーの身体に装着・連動させるKinectサンプル
- Kinectを使ったバーチャル試着室で着せ替えシミュレーション
- 人体の連続した動作を音声でキャプチャするKinectのサンプルプログラム
- お気に入りの写真に登場する、仲良しクラウディアちゃん
- 手を動かして画面上の写真を左右にスライドさせるKinectサンプル