Kinectで手の動きに合わせて波紋を発生させるサンプル
次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト4のコードを記述します。
ロジックコードを記述する
リスト4 (MainWindow.xaml.vb)
Option Strict On Imports Microsoft.Kinect
Soryboardを使用するのに必要なクラスの含まれる、System.Windows.Media.Animation名前空間をインポートします。
Imports System.Windows.Media.Animation Imports Coding4Fun.Kinect.Wpf Class MainWindow
Kinect センサーを表すメンバ変数newSensorを宣言します。
Dim newSensor As KinectSensor Dim _closing As Boolean = False
新しいStoryboardクラス用のインスタンス、strメンバ変数を宣言します。
Dim str As New Storyboard
Skeletonクラス型のメンバ変数firstSkeletonを宣言します。
Dim firstSkeleton As Skeleton
ウィンドウが読み込まれた時の処理
KinectSensorChooser1.KinectSensorChangedイベントで、Kinectセンサーが接続されているかどうかを確認します。古いセンサーが動作している時は停止させ、新しいセンサーを取得します。
パラメータのスムージング変換を行う、新しいTransformSmoothParameters型のインスタンスmyParamオブジェクトを作成します。各プロパティの値を設定します。
Smoothingでは、スムージングの量を設定します。値は0から1.0の範囲で、規定値は0.5です。値が大きいほど平滑化されますが、処理時間は増加します。
Correctionでは、平滑化の緩急を付けます。値は0から1.0の範囲で、規定値は0.5です。1.0に近いほど処理時間は早くなります。
Predictionでは、スムーズに動作させるため予測されたフレームの数を設定します。
JitterRadiusでは、ジッタ低減の半径(メートル)を設定します。デフォルトは」0.05(5cm)です。
MaxDeviationRadiusでは、フィルタされた値と生データとの誤差の許容最大値を設定します。単位はメートルで、規定値は0.04(4cm)です。
上記のプロパティを設定したmyParamオブジェクトを、SkeletonStreamのEnableメソッドに指定し、スケルトンの機能を有効にします。
ColorStream.EnableメソッドでKinectセンサーのRGBカメラの機能を有効にします。ColorImageFormat.RgbResolution640x480Fps30列挙体で「RGBフォーマットで、解像度は640×480、フレームレートは毎秒30フレーム」と設定します。
DepthStream.Enableメソッドで距離カメラの機能を有効にします。「解像度は 640 × 480、フレーム レートは 毎秒30フレーム」と設定します。
RGBカメラ、距離カメラ、骨格のフレーム更新イベントであるAllFramesReadyにsensor_AllFramesReadyイベントハンドラを指定します。
Kinectセンサーを開始します。例外が発生した場合はエラーを表示して処理を抜けます。
Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded AddHandler KinectSensorChooser1.KinectSensorChanged, Sub(kinectSender As Object, kinectArgs As DependencyPropertyChangedEventArgs) Dim oldSensor As KinectSensor = DirectCast(kinectArgs.OldValue, KinectSensor) If oldSensor Is Nothing = False Then StopKinect() End If newSensor = DirectCast(kinectArgs.NewValue, KinectSensor) If newSensor Is Nothing = True Then Return End If Dim myParam As New TransformSmoothParameters With myParam .Smoothing = 0.75F .Correction = 0.0F .Prediction = 0.0F .JitterRadius = 0.05F .MaxDeviationRadius = 0.4F End With newSensor.SkeletonStream.Enable(myParam) newSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30) newSensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30) AddHandler newSensor.AllFramesReady, AddressOf sensor_AllFramesReady Try newSensor.Start() Catch ex As Exception MessageBox.Show(ex.Message) Exit Sub End Try End Sub End Sub
RGBカメラ、距離カメラ、骨格のフレーム更新イベント
SourceImageという名前を持つImageコントロールのSourceプロパティに、e.OpenColorImageFrameメソッドで、新しいフレームのRGBカメラの情報を取得し、Coding4Fun.Kinect.Wpfの拡張メソッドであるToBitmapSourceで、myColorImageをBitmapSourceに変換して指定します。
これで、Imageコントロール内にカラー画像(実写)が表示されます。このメソッドで取得するColorImageFrameは、Usingで括るか、明示的にDisposeする必要があります。
フレームごとのスケルトンデータを表すクラスである、SkeletonFrame型のskeletonFrameData変数を宣言し、e.OpenSkeletonFrameメソッドで、新しいフレームのスケルトンの情報を取得します。
スケルトン配列の長さを取得するSkeletonArrayLengthプロパティで初期化された、新しいSkeletonクラス型の配列変数allSkeletonsを宣言します。
CopySkeletonDataToメソッドで、現在のSkeletonFrameDataにあるスケルトンデータを、指定した配列(allSkeletons)にコピーします。CopySkeletonDataToメソッドで取得されるデータはプレイヤー分取得されるため、それぞれのトラッキング状態を確認します。
Skeletonクラス用メンバ変数firstSkeletonで、スケルトンデータを持つallSkeletons配列変数内で、全ての関節の位置がトラッキングされた状態にある、先頭の要素を取得していきます。
このメソッドで取得されるSkeletonFrameは、Usingで括るか、明示的にDisposeする必要があります。
スケルトンの位置を取得するGetCameraPointプロシージャも実行します。その際、引数として全ての関節の位置がトラッキングされた状態にある、先頭の要素と、RGBカメラ、距離カメラ、スケルトンのデータを更新したイベントで渡されるAllFramesReadyEventArgsを渡します。
Private Sub sensor_AllFramesReady(ByVal sender As Object, ByVal e As AllFramesReadyEventArgs) Using myColorImage As ColorImageFrame = e.OpenColorImageFrame SourceImage.Source = myColorImage.ToBitmapSource End Using If _closing Then Return End If Try Using skeletonFrameData As SkeletonFrame = e.OpenSkeletonFrame() Dim allSkeletons As Skeleton() = New Skeleton(skeletonFrameData.SkeletonArrayLength - 1) {} skeletonFrameData.CopySkeletonDataTo(allSkeletons) firstSkeleton = (From s In allSkeletons Where s.TrackingState = SkeletonTrackingState.Tracked Select s).FirstOrDefault() End Using If firstSkeleton Is Nothing Then Return End If GetCameraPoint(firstSkeleton, e) Catch Exit Sub End Try End Sub
スケルトンの位置を取得する処理
Kinectセンサーの距離カメラから、距離カメラのフレームデータを表すDepthImageFrameクラス型のdepth変数を宣言し、OpenDepthImageFrameメソッドで、新しいフレームの距離カメラの情報を取得します。
距離データのピクセル座標、および距離、プレイヤーIDを表す、DepthImagePoint構造体のleftDepthPoint変数を宣言し、MapFromSkeletonPointメソッドで、スケルトンの座標を、距離カメラの座標に変換します。この場合、左手の位置を距離カメラの座標に変換します。同じく右手の位置も距離カメラの座標に変換します。MapFromSkeletonPointメソッドの書式は下記です。
DepthImagePoint. MapFromSkeletonPoint(変換するスケルトンの座標)
次に、RGBカメラのX-Y座標データを表す、ColorImagePoint構造体の変数leftColorPointを宣言し、MapToColorImagePointメソッドで、左手の距離カメラの座標をRGBカメラの座標に変換し、leftColorPointで取得します。書式は下記です。
DepthImageFrame.MapToColorImagePoint(距離カメラのX座標,現在の 距離カメラの Y 座標,RGBカメラフォーマット)
この場合、左手の距離カメラのX座標と、Y座標、RGBフォーマットで解像度が640×480、フレーム レートは 毎秒30フレームに変換しています。同様に右手に対しても同じ処理を行います。距離カメラのデータをRGBカメラ(実写)のデータにマップします。
MapToSkeletonPointメソッドで、距離カメラの座標に対応する、スケルトンの座標を取得します。書式は下記の通りです。
DepthImageFrame.MapToSkeletonPoint(距離カメラのX座標,距離カメラのY座標)
距離カメラの座標に対応する、スケルトンの座標を取得して、プレイヤーの右手と距離カメラとの距離を取得し、変数rightZに格納します。同じく左手の距離を取得してleftZに格納します。
右手のKinectセンサーからの距離が、センサーに30cm近い左手の距離よりも遠くに位置する場合、つまり、右手が左手よりも距離カメラに近かった場合に、RippleEffectGoプロシージャを実行します。
その際、引数としてRGBカメラの座標に変換された、右手のXとY座標の位置を渡します。このメソッドで取得するDepthImageFrameは、Usingで括るか、明示的にDisposeする必要があります。
Private Sub GetCameraPoint(ByVal firstSkeleton As Skeleton, ByVal e As AllFramesReadyEventArgs) Using depth As DepthImageFrame = e.OpenDepthImageFrame() If depth Is Nothing OrElse kinectSensorChooser1.Kinect Is Nothing Then Return End If Dim leftDepthPoint As DepthImagePoint = depth.MapFromSkeletonPoint(firstSkeleton.Joints(JointType.HandLeft).Position) Dim rightDepthPoint As DepthImagePoint = depth.MapFromSkeletonPoint(firstSkeleton.Joints(JointType.HandRight).Position) Dim leftColorPoint As ColorImagePoint = depth.MapToColorImagePoint(leftDepthPoint.X, leftDepthPoint.Y, ColorImageFormat.RgbResolution640x480Fps30) Dim rightColorPoint As ColorImagePoint = depth.MapToColorImagePoint(rightDepthPoint.X, rightDepthPoint.Y, ColorImageFormat.RgbResolution640x480Fps30) Dim rightZ = depth.MapToSkeletonPoint(rightDepthPoint.X, rightDepthPoint.Y).Z Dim leftZ = depth.MapToSkeletonPoint(leftDepthPoint.X, leftDepthPoint.Y).Z Dim rightColorPointX = rightColorPoint.X Dim rightColorPointY = rightColorPoint.Y If rightZ > leftZ - 0.3 Then RipplEffectGo(rightColorPointX, rightColorPointY) Else str = Nothing End If End Using End Sub
RippleEffect処理を実行する処理
FindResourceメソッドでRippleEffectStoryboardという名前のリソースを見つけ、Storyboardにキャストします。Point構造体型の変数myPositionを宣言し、myPositionのXとY座標に、RGBカメラの座標に変換された、右手のXとY座標の位置を、NameがSourceImageのImageコントロールの、WidthとHeightで除算した値を指定します。
ImageコントロールのWidthとHeightの値で除算しているのは、RippleEffectの効果が、640×480の範囲内で発生させるためです。Point構造体は、2次元空間でのxとy座標のペアを表します。
RippleEffectのCenterプロパティにmyPositionオブジェクトを指定します。RepeatBehaviorプロパティにForeverを指定して、永遠にRippleEffectを繰り返すよう指定し、BeginメソッドでRippleEffectのストーリーボードを実行します。これで、右手でタップした位置を中心に波紋が広がります。
Private Sub RipplEffectGo(rightColorPositionX As Integer, rightColorPositionY As Integer) str = DirectCast(FindResource("RippleEffectStoryboard"), Storyboard) Dim myPosition As Point myPosition.X = righColortPositionX / 640 myPosition.Y = rightColorPositionY / 480 myRippleEffect.Center = myPosition str.RepeatBehavior = RepeatBehavior.Forever str.Stop() str.Begin() End Sub End Class
ウィンドウが閉じられた時の処理
Kinectセンサーの動作を停止するStopKinectプロシージャを実行します。
Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing StopKinect() End Sub
Kinectセンサーの動作を停止する処理
Kinectセンサーが動作している場合は、AllFramesReadyイベントを解除し、Kinectセンサーを停止します。最後にリソースを解放します。
Private Sub StopKinect() If newSensor IsNot Nothing Then If newSensor.IsRunning = True Then RemoveHandler newSensor.AllFramesReady, AddressOf sensor_AllFramesReady newSensor.Stop() newSensor.Dispose() End If End If End Sub End Class
今回のサンプルは以上で終了です。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- マウスクリックによるRippleEffect特殊効果
- Kinectで手の動きに合わせてモニタ上の画像を動かすサンプル
- Kinectで人体を認識して棒人間を動かすサンプル
- Kinectを使って、顔の動きを認識して画面に表示する
- Kinectで手の動きとカーソルを連動して操作するサンプル
- 声で選んだアイテムをプレイヤーの身体に装着・連動させるKinectサンプル
- Kinectを使って、自分の手のひらに小さな分身を出現させてみる
- 人物特定に使える!?実際の映像で顔を認識するKinectプログラム
- Kinectによる深度データの取得・表示と、モーターを動かすサンプル
- プレイヤーの身体パーツを判別するKinectサンプル