Kinectを使って、顔の動きを認識して画面に表示する
※前ページからの続きです。 新しいフレームのRGBカメラの情報、新しいフレームの距離カメラの情報、新しいフレームのスケルトンの情報を取得します。距離カメラのイメージフォーマットが、距離カメラのイメージフレームのデータタイプ、解像度、フレームレートと同じでなかった場合は、距離カメラのイメージフォーマットを距離カメラのイメージフレームのフォーマットと同じにします。 同様に、RGBカメラのイメージフォーマットが、RGBカメラのイメージフレームのデータタイプ、解像度、フレームレートと同じでなかった場合は、RGBカメラのイメージフォーマットをRGBカメラのイメージフレームのフォーマットと同じにします。 距離カメラのフレームのピクセルデータを取得するためのShort配列を確保(Short配列の長さはmyDepthImageFrame.PixelDataLength- 1で取得)し、myDepthImageに格納します。 同様に、RGBカメラのフレームのピクセルデータを取得するためのバイト配列を確保(バイト配列の長さはmyColorImageFrame.PixelDataLength - 1で取得)し、myColorImageに格納します。 スケルトンのフレームの、スケルトン配列を確保(スケルトン配列の長さはmySkeletonFrame. SkeletonArrayLength - 1で取得)し、skeletonDataに格納します。 各フレームからCopyPixelDataToメソッドを呼び出し、ピクセルデータを取得します。CopyPixelDataToメソッドは、ピクセルデータの長さを使用して、事前に割り当てられた配列へ、ピクセルごとの深度データやRGBデータをコピーします。 追跡者と、現在のフレーム情報を持つ追跡者のリストを更新します。スケルトンの情報を持つskeletonData内をスケルトン型の変数mySkeletonで反復処理しながら以下の処理を行います。 スケルトンのトラッキング状態が、トラッキングされているか、ジョイントのトラッキングはしておらず、プレイヤー位置のみトラッキングしている(Nearモード時)場合の処理です。追跡されたスケルトンにトラッキングIDが含まれていた場合は、Addメソッドで、追跡されているスケルトンに、指定したキー(スケルトンID)と値(SkeletonFaceTrackerのインスタンス)をディクショナリに追加します。 SkeletonFaceTrackerの新しいインスタンスmySkeletonFaceTrackerを作成します。TryGetValueメソッドで、スケルトンのトラッキングIDに関連付けられている値があった場合は、RGBフォーマット、RGBイメージのバイト配列、距離カメラのフォーマット、深度イメージのShort配列、スケルトン、を引数にOnFrameReadyプロシージャを実行します。最後に追跡されたフレームにスケルトンフレームのフレームナンバーを格納します。 各追跡者に更新されたフレームを与えます。 要素の描画を無効にして、完全に新しいレイアウトパスを強制するInvalidateVisualメソッドを呼び出します。 古いセンサーが動いている場合は、RemoveHandlerステートメントで、イベントを解除します。新しいKinectセンサーが動いている場合は、AddHandlerステートメントで、RGBカメラ、距離カメラ、スケルトンのフレームが更新された時に発生するAllFramesReadyイベントにイベントハンドラを追加します。 次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト3のコードを記述します。 Bgr32形式は1ピクセルあたりのビット数が32bitのRGB形式で、先頭から1バイト(8bit)ずつに青、緑、赤、の情報が入っています。各カラーチャネルに割り当てられるbits per pixel(BBP)が8であるため、Bgr32を8で除算した4バイトの値をメンバ変数BrgPixelに格納しておきます。青、緑、赤では24ビットしか使用されません、残りの8ビットはAlphaに使用されることが多いですが、このサンプルでは使用していません。また32ビットを8で除算した4(バイト)を直接指定しても問題ありません。 KinectSensorChooserクラスの新しいインスタンスsensorChooserメンバ変数を宣言します。KinectSensorChooserクラスはアプリケーションからKinectセンサーを検出するクラスです。 Kinectセンサーを表すメンバ変数Kinectを宣言しておきます。 FaceTrackingViewer1コントロールに、ユーザーコントロールのFaceTrackingViewer.xaml.vb内で定義したWPFプロパティシステムに登録される依存関係プロパティを表す、DependencyPropertyクラス型のKinectPropertyをバインドします。AddHandlerステートメントでKinectセンサーが検出された時に発生するKinectChangedイベントにイベントハンドラを追加します。KinectSensorChooserを開始します。 新しいKinectセンサーをメンバ変数Kinectに格納します。新しいKinectセンサーが検出された場合は、RGBと距離カメラを有効にします。Nearモードを有効にします。SkeletonTrackingMode.Seatedで、椅子に座った上半身の状態でもスケルトンの認識可能にします。スケルトンを有効にします。AddHandlerステートメントで、RGBカメラ、距離カメラ、スケルトンフレームが更新された時に発生するAllFramesReadyイベントにイベントハンドラを追加します。 e.OpenColorImageFrameで、新しいフレームのRGBカメラの情報を取得し、e.OpenDepthImageFrameで、新しいフレームの距離カメラの情報を取得します。これらのメソッドで取得するcolorImagerFrameやdepthImageFrameは、Usingで括るか、明示的にDisposeする必要があります。Kinect センサーを取得します。 RGBカメラと距離カメラの両方に情報があった場合は、バイト配列型の変数getBackgroundMaskを宣言して、BackgroundMask関数を実行して戻り値を取得します。BackgroundMask関数には引数として、Kinect センサー、RGBカメラのフレーム情報、距離カメラのフレーム情報を渡します。 NameがcolorImageのImageコントロールのSourceプロパティに、ピクセルデータをビットマップに変換して指定します。 BitmapSource.Createメソッドの書式は下記の通りです。 BitmapSource.Create(RGBカメラで取得したフレーム幅,RGBカメラで取得したフレームの高さ,ビットマップの水平ドット(dpi),ビットマップの垂直ドット(dpi),ビットマップのピクセルフォーマット,ビットマップのパレット,ビットマップイメージのコンテンツを表すバイト配列,ビットマップのストライド) 「ビットマップのピクセルフォーマット」には、PixelFormats.Bgr32を指定します。Bgr32 ピクセル形式を取得します。Bgr32 は、bits per pixel(BPP)が 32 の sRGB 形式です。各カラー チャネル(青、緑、および赤)に割り当てられる bits per pixel(BPP)は 8 です。 「ビットマップイメージのコンテンツ」を表すバイト配列にBackgroundMaskの戻り値である、バイト配列を指定します。 「ビットマップのストライド」は1ラインあたりのバイト数を表しますので、この場合、colorImageFrame.Width * colorImageFrame.BytesPerPixelと指定します。BytesPerPixelプロパティでRGBカメラの1ピクセルあたりのバイト数を取得して、それにRGBカメラで取得されたフレームの幅を乗算した値を指定します。 BytesPerPixelは1ピクセルあたりのビット数が32bitのRGB形式で、先頭から1バイト(8bit)ずつに青、緑、赤、(残りの1バイト(8bit)はAphaチャネル等に利用されることがありますが、このサンプルでは使用していません)の情報が入っています。1バイトは8ビットですので32÷8=4バイトの値になります。よって640×4=2560となり、2560の値を直接指定しても問題ありません。 Kinectセンサーの検出を停止します。ユーザーコントロールであるFaceTrackingViewer1のリソースを解放します。 RGBカメラの処理を行うクラスのインスタンスを取得します。バイト配列変数colorPixelにRGBカメラのピクセルデータのバイト長分の配列を作成します。CopyPixelDataToメソッドで、RGBカメラのフレームのピクセルデータを取得します。CopyPixelDataToメソッドは、ピクセルデータの長さを使用して、事前に割り当てられた配列へ、ピクセルごとの深度データやRGBデータをコピーします。 Dim outputColor As Byte() = New Byte(colorPixel.Length - 1) {}で、RGBカメラの画像を基に表示用のバッファを作成します。 変数indexを、0から、RGBカメラのピクセルデータのバイト長分の配列を保持している、outputColor.Length分、反復処理を行い、下記の処理を実行します。 繰り返し変数iに対応する、Byte型の配列変数であるRGBカメラの画像(outputColor)に、0を指定し背景を黒にしています。変数iを4バイト分ずつ加算します。戻り値は、表示用のコンテンツを表すバイト配列を取得したoutputColorです。 以上で今回のサンプルは終了です。 編集部より:サンプルプログラムへのリンクが誤っていたため、修正しました。(2012.10.01)RGBカメラ、距離カメラ、スケルトンのフレームが更新された時の処理
Private Sub OnAllFramesReady(sender As Object, e As AllFramesReadyEventArgs)
Dim myColorImageFrame As ColorImageFrame = Nothing
Dim myDepthImageFrame As DepthImageFrame = Nothing
Dim mySkeletonFrame As SkeletonFrame = Nothing
Try
myColorImageFrame = e.OpenColorImageFrame()
myDepthImageFrame = e.OpenDepthImageFrame()
mySkeletonFrame = e.OpenSkeletonFrame()
If myColorImageFrame Is Nothing OrElse myDepthImageFrame Is Nothing OrElse mySkeletonFrame Is Nothing Then
Return
End If
If myDepthImageFormat <> myDepthImageFrame.Format Then
myDepthImage = Nothing
myDepthImageFormat = myDepthImageFrame.Format
End If
If myColorImageFormat <> myColorImageFrame.Format Then
myColorImage = Nothing
myColorImageFormat = myColorImageFrame.Format
End If
If myDepthImage Is Nothing Then
myDepthImage = New Short(myDepthImageFrame.PixelDataLength - 1) {}
End If
If myColorImage Is Nothing Then
myColorImage = New Byte(myColorImageFrame.PixelDataLength - 1) {}
End If
If skeletonData Is Nothing OrElse skeletonData.Length <> mySkeletonFrame.SkeletonArrayLength Then
skeletonData = New Skeleton(mySkeletonFrame.SkeletonArrayLength - 1) {}
End If
myColorImageFrame.CopyPixelDataTo(myColorImage)
myDepthImageFrame.CopyPixelDataTo(myDepthImage)
mySkeletonFrame.CopySkeletonDataTo(skeletonData)
For Each mySkeleton As Skeleton In skeletonData
If mySkeleton.TrackingState = SkeletonTrackingState.Tracked OrElse mySkeleton.TrackingState = SkeletonTrackingState.PositionOnly Then
If trackedSkeletons.ContainsKey(mySkeleton.TrackingId) = False Then
trackedSkeletons.Add(mySkeleton.TrackingId, New SkeletonFaceTracker())
End If
Dim mySkeletonFaceTracker As New SkeletonFaceTracker
If trackedSkeletons.TryGetValue(mySkeleton.TrackingId, mySkeletonFaceTracker) = True Then
mySkeletonFaceTracker.OnFrameReady(Kinect, myColorImageFormat, myColorImage, myDepthImageFormat, myDepthImage, mySkeleton)
mySkeletonFaceTracker.LastTrackedFrame = mySkeletonFrame.FrameNumber
End If
End If
Next
InvalidateVisual()
Finally
If myColorImageFrame Is Nothing = False Then
myColorImageFrame.Dispose()
End If
If myDepthImageFrame Is Nothing = False Then
myDepthImageFrame.Dispose()
End If
If mySkeletonFrame Is Nothing = False Then
mySkeletonFrame.Dispose()
End If
End Try
End Sub
Kinectセンサーのデータを受信した時の処理
Private Sub OnSensorChanged(oldSensor As KinectSensor, newSensor As KinectSensor)
If oldSensor Is Nothing = False Then
RemoveHandler oldSensor.AllFramesReady, AddressOf OnAllFramesReady
End If
If newSensor Is Nothing = False Then
AddHandler newSensor.AllFramesReady, AddressOf OnAllFramesReady
End If
End Sub
End Class
ロジックコードを記述する
リスト2 (MainWindow.xaml.vb)
Option Strict On
Imports Microsoft.Kinect
Imports Microsoft.Kinect.Toolkit
Class MainWindow
Dim Bgr32BytesPerPixel As Integer = CInt((PixelFormats.Bgr32.BitsPerPixel) / 8)
Dim sensorChooser As New KinectSensorChooser()
Dim Kinect As KinectSensor
ウィンドウが読み込まれた時の処理
Public Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Dim faceTrackingViewerBinding = New Binding("Kinect") With {.Source = sensorChooser}
FaceTrackingViewer1.SetBinding(FaceTrackingViewer.KinectProperty, faceTrackingViewerBinding)
AddHandler sensorChooser.KinectChanged, AddressOf SensorChooserOnKinectChanged
sensorChooser.Start()
End Sub
Kinectセンサーが検出された時の処理
Private Sub SensorChooserOnKinectChanged(sender As Object, e As KinectChangedEventArgs)
Kinect = e.NewSensor
If Kinect Is Nothing = False Then
Kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30)
Kinect.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30)
Kinect.DepthStream.Range = DepthRange.Near
Kinect.SkeletonStream.EnableTrackingInNearRange = True
Kinect.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated
Kinect.SkeletonStream.Enable()
AddHandler Kinect.AllFramesReady, AddressOf KinectSensorOnAllFramesReady
End If
End Sub
RGBカメラ、距離カメラ、スケルトンフレームが更新された時に発生するイベント
Private Sub KinectSensorOnAllFramesReady(sender As Object, e As AllFramesReadyEventArgs)
Using colorImageFrame = e.OpenColorImageFrame()
Using depthImageFrame = e.OpenDepthImageFrame
Dim kinect As KinectSensor = TryCast(sender, KinectSensor)
If kinect Is Nothing = True Then
Return
End If
If colorImageFrame Is Nothing = True Then
Return
End If
If (colorImageFrame IsNot Nothing) AndAlso (depthImageFrame IsNot Nothing) Then
Dim getBackgroundMask As Byte() = BackgroundMask(kinect, colorImageFrame, depthImageFrame)
colorImage.Source = BitmapSource.Create(colorImageFrame.Width, colorImageFrame.Height, 96, 96, PixelFormats.Bgr32, Nothing, getBackgroundMask, colorImageFrame.Width * colorImageFrame.BytesPerPixel) 'Me.colorImageWritableBitmap
End If
End Using
End Using End Sub
ウィンドウが閉じられた時の処理
Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing
sensorChooser.Stop()
FaceTrackingViewer1.Dispose()
End Sub
表示用のコンテンツを表すバイト配列を取得する関数
Private Function BackgroundMask(kinect As KinectSensor, colorFrame As ColorImageFrame, depthFrame As DepthImageFrame) As Byte()
Dim colorStream As ColorImageStream = kinect.ColorStream
Dim colorPixel As Byte() = New Byte(colorFrame.PixelDataLength - 1) {}
colorFrame.CopyPixelDataTo(colorPixel)
Dim outputColor As Byte() = New Byte(colorPixel.Length - 1) {}
Dim i As Integer = 0
While i < outputColor.Length
outputColor(i) = 0
outputColor(i + 1) = 0
outputColor(i + 2) = 0
i = i + Bgr32BytesPerPixel
End While
Return outputColor
End Function
End Class
顔の動きを追跡するKinectサンプル
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- 人物を切り抜いて画面に表示するKinectサンプル
- 人物特定に使える!?実際の映像で顔を認識するKinectプログラム
- Kinectで人体を認識して棒人間を動かすサンプル
- Kinectを使って、自分の手のひらに小さな分身を出現させてみる
- プレイヤーの身体パーツを判別するKinectサンプル
- Kinectで手の動きに合わせてモニタ上の画像を動かすサンプル
- Kinectで結成したマイ・ダンスチームを、サンプルを見ながら実際の背景に合成してみよう
- Kinectの音声認識を使って、プレイヤーを分離、結合させるデモを試してみる
- これであなたもダンスグループの一員!?Kinectで自分を分身させるプログラムを作る
- 人体の連続した動作を音声でキャプチャするKinectのサンプルプログラム