センサーの範囲内にいる人間を見つけて撮影・保存するKinectサンプル
前ページからの続きです。
画像データとXMLファイル(リスト4)を保存する処理
ListBox内に項目(年月日時分秒)が表示されている場合の処理です。
RenderTargetBitmapクラスの新しいインスタンスを作成します。その際下記の書式で初期化します。RenderTargetBitmapクラスはVisual オブジェクトをビットマップに変換します。
RenderTargetBitmap(ビットマップの幅,ビットマップの高さ,ビットマップの水平DPI,ビットマップの垂直DPI,ビットマップの形式)
「ビットマップの形式」には、PixelFormats.Pbgra32を指定します。PixelFormats.Pbgra32は、Pbgra32 ピクセル形式を取得します。Pbgra32 は、bits per pixel(BPP)が 32 の sRGB 形式です。各カラー チャネル(青、緑、赤、およびアルファ)に割り当てられるbits per pixel(BPP)は 8 です。各カラー チャネルは、アルファ値によって左側から乗算されます。
RenderメソッドでImage1をレンダリングします。新しいJpegBitmapEncoderクラスのインスタンスmyJpgオブジェクトを作成します。JpegBitmapEncoderクラスは、JPEG形式のイメージのエンコードに使用されるエンコーダーを定義するクラスです。
myJpg.Frames.Add(BitmapFrame.Create(bmp))で、エンコーダーにフレームを追加していきます。
システムの特別なフォルダである「マイピクチャ」フォルダへのディレクトリパスを取得し、変数dirに格納しておきます。「マイピクチャ」フォルダ内の「KINECT」サブフォルダへのパスを変数saveDirに格納しておきます。
KINECTフォルダと、ListBoxより選択された項目に文字列.jpgを連結したファイルを、新規作成モードで開き、JpegBitmapEncoderクラスのSaveメソッドで、ビットマップ イメージを指定した Stream にエンコードします。これで、年月日時分秒.jpgファイルが作成されます。
変数outTimeにListBoxより選択された項目を格納し、inTime変数にKinectセンサーの視界に人の現れた時刻を格納しておきます。
KINECTフォルダ内にImageFileList.xmlファイルが存在していなかった場合、そして、Kinectセンサーの視界に人が入った時間と、ListBoxに表示されている時間が異なる場合は、XML宣言とルート要素、要素とその子要素とを作成し、変数inTimeの値と変数imageFileNameの値を指定して、XMLを作成し、保存します。[データ表示]ボタンの使用を可能にします。
すでにimageFileList.xmlファイルが存在する場合は、そのファイルを読み込み、要素とその子要素とに値を指定して、読み込んだXMLに追加保存します。[データ表示]ボタンの使用を可能にします。TextBlockに「記録中。」と表示します。
Private Sub DataSave() If ListBox1.Items.Count > 0 Then Dim bmp = New RenderTargetBitmap(CInt(Image1.Width), CInt(Image1.Height), 96, 96, PixelFormats.Pbgra32) bmp.Render(Image1) Dim myJpg = New JpegBitmapEncoder myJpg.Frames.Add(BitmapFrame.Create(bmp)) Dim dir As String = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) Dim saveDir As String = Path.Combine(dir, "KINECT") Using fs As FileStream = File.Open(Path.Combine(saveDir, imageFileName), FileMode.Create) myJpg.Save(fs) End Using outTime = ListBox1.SelectedItem.ToString inTime = inTextBlock.Text If File.Exists(Path.Combine(saveDir, "ImageFileList.xml")) = False Then Dim xmldoc As XDocument = <?xml version="1.0" encoding="utf-8"?> <人物記録> <情報> <入時間><%= inTime %></入時間> <画像名><%= imageFileName %></画像名> </情報> </人物記録> xmldoc.Save(Path.Combine(saveDir, "ImageFileList.xml")) Button1.IsEnabled = True TextBlock1.Text = "記録中。" Else Dim readXmldoc As XElement = XElement.Load(Path.Combine(saveDir, "ImageFileList.xml")) Dim addXml As XElement = <情報> <入時間><%= inTime %></入時間> <画像名><%= imageFileName %></画像名> </情報> readXmldoc.Add(addXml) readXmldoc.Save(Path.Combine(saveDir, "ImageFileList.xml")) Button1.IsEnabled = True TextBlock1.Text = "記録中。" End If End If End Sub
[データ表示]ボタンがクリックされた時の処理
DataShowWindowを表示します。
Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click Dim dataPage As New DataShowWindow dataPage.Show() End Sub
ListBox内の項目が選択された時のイベント
ListBox内に項目名が表示されている場合は、その項目名に文字列.jpgを連結して、変数imageFileNameに格納します。
Private Sub ListBox1_SelectionChanged(sender As Object, e As System.Windows.Controls.SelectionChangedEventArgs) Handles ListBox1.SelectionChanged If ListBox1.Items.Count > 0 Then imageFileName = ListBox1.SelectedItem.ToString & ".jpg" End If End Sub
ウィンドウが閉じられる時に発生するイベント
Kinectセンサーが動いている時は、AllFramesReadyイベントの登録を解除し、StopメソッドでKinectセンサーの動作を停止します。最後にDisposeメソッドでリソースを解放します。
Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing If kinect Is Nothing = False Then If kinect.IsRunning = True Then RemoveHandler kinect.AllFramesReady, AddressOf kinect_AllFramesReady kinect.Stop() kinect.Dispose() End If End If End Sub End Class
リスト4 「マイマイピクチャ」のKINECTフォルダに保存されたImageFileList.xmlの構造
<?xml version="1.0" encoding="utf-8"?> <人物記録> <情報> <入時間>2012年06月21日17時50分53秒</入時間> <画像名>2012年06月21日17時50分54秒.jpg</画像名> </情報> ~ <情報></情報>繰り返し~ </人物記録>
次に、ソリューションエクスプローラー内のDataShowWindow.xamlを展開して表示される、DataShowWindow.xaml.vbをダブルクリックしてリスト4のコードを記述します。
ロジックコードを記述する
リスト4 (DataShowWindow.xaml.vb)
Option Strict On Imports System.IO
ImageInfoクラスにOutRoomとImageNameプロパティを定義しておきます。このプロパティをTextBlockのTextやImageのSourceプロパティにバインドしています。
Public Class ImageInfo Property OutRoomTime As String Property ImageName As String End Class
ウィンドウが読み込まれた時の処理
ListBox内をクリアします。システムの特別なフォルダである「マイピクチャ」フォルダへのディレクトリパスを変数dirに格納しておきます。「マイピクチャ」フォルダ内のサブフォルダKINECTへのパスを変数fileDirに格納しておきます。
KINECTフォルダ内のImageFileList.xmlを読み込みます。ImageInfoクラス型の新しいリストであるmyImageInfoオブジェクトを作成します。読み込んだXMLの要素コレクション内の、重複しない(Distinct)要素コレクション内を、変数resultで反復処理しながら、以下の処理を繰り返します。
要素の内容テキストである値(年月日時分秒.jpg)のファイルが存在する場合は、新しいImageInfoクラスのOutRoomプロパティに、Path.GetFileNameWithoutExtensionメソッドで、.jpgという拡張子を除いた要素の値を指定します。
ImageNameプロパティにKINECTフォルダを連結した要素の値を指定して、AddメソッドでmyImageInfoオブジェクトに追加していきます。ListBoxのItemsSourceプロパティにmyImageInfoオブジェクトを指定すると、ListBox内に日時と画像が表示されます。
Public Class DataShowWindow Private Sub DataShowWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded ListBox1.Items.Clear() Dim dir As String = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) Dim fileDir As String = Path.Combine(dir, "KINECT") Dim xmldoc As XElement = XElement.Load(Path.Combine(fileDir, "ImageFileList.xml")) Dim myImageInfo As New List(Of ImageInfo) For Each result In From c In xmldoc.Descendants("情報") Select c.<画像名>.Value Distinct If File.Exists(Path.Combine(fileDir, result.Value)) = True Then With myImageInfo .Add(New ImageInfo With {.OutRoomTime = Path.GetFileNameWithoutExtension(result), .ImageName = Path.Combine(fileDir, result)}) End With End If Next ListBox1.ItemsSource = myImageInfo End Sub End Class
「マイピクチャ」のKINECTフォルダ内のImageFileList.xmlを見るとわかりますが、同じ時刻のデータが重複して記録されています。それでLINQクエリーでDistinct句を使って、データを取り出す際、重複しないデータを取り出して表示しています。
以上で今回のサンプルは終了です。
センサーの範囲内にいる人間を見つけて撮影・保存するKinectサンプル
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Windows Phoneで自宅の様子をリモート監視するKinectプログラムを作ってみる
- タッチパネルでドラッグ&ドロップを使う汎用的なサンプル
- カメラで写した写真を分離ストレージに保存し、写真の一覧を表示する
- 撮影した写真を分離ストレージとPicturesHUBに保存する
- 写真をハート型に切り抜いて撮影するサンプル
- 声で選んだアイテムをプレイヤーの身体に装着・連動させるKinectサンプル
- Kinectを使ったバーチャル試着室で着せ替えシミュレーション
- 人体の連続した動作を音声でキャプチャするKinectのサンプルプログラム
- お気に入りの写真に登場する、仲良しクラウディアちゃん
- 手を動かして画面上の写真を左右にスライドさせるKinectサンプル