Kinectを使って、顔の動きを認識して画面に表示する
VS2010のメニューから「プロジェクト(P)/参照の追加(R)」と選択して、各種コンポーネントを追加しておきます。今回追加するのは、Microsoft.KinectとMicrosoft.Kinect.Toolkit、Microsoft.Kinect.Toolkit.FaceTrackingの3つです。「.NET」タブ内に表示されていないDLLファイルは「参照」タブからDLLファイルを指定します。 Microsoft.Kinect.dllは、C:\Program Files\Microsoft SDKs\Kinect\v1.5\Assemblies内に存在しますので、これを指定します。 Microsoft.Kinect.Toolkit.dllは Microsoft.Kinect.Toolkit.FaceTracking.dllは、Kinect for Windows Developer Toolkit 1.5.1に含まれる、Face Tracking Basics-WPFをインストールしたディレクトリの、\Face\FaceTrackingBasics-WPF\bin\x86\Debug\フォルダ内に存在していますので、これを指定してください。 次に、ソリューションエクスプローラー内のFaceTrackingViewer.xamlを展開して表示される、FaceTrackingViewer.xaml.vbをダブルクリックしてリスト2のコードを記述します。 ※注意事項:このサンプルを作成して実行する前に、必ず下記のことを行ってください。これは筆者の環境では発生していますが、ひょっとしたら、皆さんの環境では発生しないかもしれません。 WPFプロパティシステムに登録される依存関係プロパティを表す、DependencyPropertyクラス型のKinectPropertyを宣言します。依存プロパティとは「ほかの要素の値に依存してプロパティの値を決定する機構」のことを差します。Public Static Readonly フィールドで宣言します。DependencyProperty.Register メソッドで依存関係プロパティを登録します。 DependencyProperty.Register メソッドの書式は下記の通りです。 DependencyProperty.Register(登録する依存プロパティ名,プロパティの型,依存プロパティを登録している所有者型,依存関係プロパティのプロパティメタデータ) ここでは、「登録する依存プロパティ名」に「Kinect」、「プロパティの型」に「KinectSensor」、「所有者型」に「FaceTrackingVierer」を指定しています。「プロパティメタデータ」内では以下の処理を行っています。PropertyMetadata を定義することにより、クラスで依存関係プロパティの動作(既定値、プロパティ システム コールバックなど)を定義できます。 指定した既定値と PropertyChangedCallback(依存関係プロパティの有効なプロパティ値が変更された時に呼び出されるコールバックを表す)実装参照を使用して、PropertyMetadata クラスの新しいインスタンスを初期化します。PropertyChangedCallbackでプロパティの有効値が変更される時(OnSensorChanged)にプロパティシステムによって必ず呼び出されるハンドラ実装への参照を行います。 符号なし32 ビット(4 バイト)の整数型MaxMissedFramesを定数メンバ変数として宣言し、100で初期化しておきます。 キーがInteger型で、値がSkeletonFaceTrackerのコレクションを表す、新しいDictionary ジェネリック クラスのインスタンスtrackedSkeletonsメンバ変数を宣言します。SkeletonFaceTrackerクラスは、このコード内で定義されている、顔の骨格を追跡する者を表すクラスです。 Byte型の配列メンバ変数myColorImageを宣言します。 RGBカメラの解像度とフレームレートを表す列挙体であるColorImageFormat型のメンバ変数myColorImageFormatを宣言し、ColorImageFormatを未定義のフォーマットに指定しておきます。 Short型の配列メンバ変数myDepthImageを宣言します。 距離カメラの解像度とフレームレートを表す列挙体であるDepthImageFormat型のメンバ変数myDepthImageFormatを宣言し、DepthImageFormatを未定義のフォーマットに指定しておきます。 ブール型のメンバ変数myDisposeを宣言します。 スケルトン型の配列メンバ変数skeletonDataを宣言します。 顔を三角形で構成するクラスであるFaceTriangleクラス型のShared配列変数faceTrianglesを宣言します。 特徴点と2 次元平面に点を定義する浮動小数点座標ペア(x座標とy座標)を表す型を持つ、EnumIndexableCollectionクラス型の変数facePointsを宣言します。 顔の追跡者を表すクラスであるFaceTrackerクラス型のmyFaceTracker変数を宣言します。 ブール型の変数lastFaceTrackSucceededを宣言します。 スケルトンの追跡状態を表す列挙型のmySkeletonTrackingState変数を宣言します。 Integer型のプロパティLastTrackedFrameを宣言します。 顔が追跡されている場合は、リソースを解放し、オブジェクトとの関連付けを解除します。 2次元空間でのx 座標とy 座標のペアを表すSystem.Windows.Point型の新しいリストである、faceModelPtsを作成します。同様に、顔を三角形で構成するFaceModelTriangle型の新しいリストであるfaceModelを作成します。 顔を三角形で構成するクラスであるFaceTriangleクラス型のShared配列変数faceTriangles内を変数tで反復処理しながら以下の処理を繰り返します。 System.Windows.Point型を P1、P2、P3というPublic変数で定義しているFaceModelTriangle構造体の新しいインスタンス、triangleを作成し、三角形を作成します。作成した三角形をFaceModelTriangle構造体のインスタンスであるfaceModelオブジェクトにAddメソッドで追加していきます。 Geometryオブジェクトで構成される複合ジオメトリーを表す、新しいGeometryGroupのインスタンス、faceModelGroupを作成します。変数iで、三角形の追加されたfaceModelオブジェクトの個数分反復処理を行います。新しいGeometryGroupのインスタンス、faceTriangleを作成し、線のジオメトリーを表す、新しいLineGeometryを作成して、生成された三角形をつないでいきます。つないだ三角形をGeometryGroupのインスタンス、faceModelGroupオブジェクトのAddメソッドで追加していきます。 ビジュアルコンテンツを記述するDrawingContextクラスのDrawGeometry メソッドで、指定したBrush およびPen を使用して、指定したGeometry を描画します。書式は下記の通りです。 DrawingContext.DrawGeometry(Geometry の塗りつぶしに使用する Brush[省略可能], Geometry のストロークに使用するPen[省略可能], 描画する Geometry) 上記の書式に従って、描画するGeometryを赤のBrushで太さ2の赤のPenで描画しています。 追跡されたスケルトンの状態を変数mySkeletonTrackingStateに保持させておきます。スケルトンの状態が追跡されていない場合は、何も行いません。 顔が追跡されていない場合は、これ以後に定義しているkinectプロパティで初期化された新しいFaceTrackerのインスタンスを作成します。 顔が追跡されている場合は、顔の追跡されたフレームを表すクラスであるFaceTrackFrame型の変数frameを宣言し、顔を追跡するFaceTrackerクラスのTrackメソッドで、指定したRGBフォーマット、Byte型のRGBイメージデータ、距離カメラのフォーマット、Short型の距離カメラのデータ、およびスケルトンを使用して追跡を行います。 ブール型のlastFaceTrackSucceeded変数には、顔のフレーム追跡が成功した値を格納しておきます。 顔のフレーム追跡が成功し、顔を三角形で構成するクラスであるFaceTriangleの変数faceTrianglesにデータがあった場合は、三角形を取得してfaceTrianglesに格納します。特徴点と2 次元平面に点を定義する浮動小数点座標ペア(x 座標と y 座標)を表す型を持つ、EnumIndexableCollectionクラス型の変数facePointsに、frame.GetProjected3DShapeで、FeaturePointがPointF データ構造体とぺアになっているフレームが返されます。 System.Windows.Point型のP1,P2,P3をPublic変数として宣言しています。 Finalizeメソッドは、Object がガベージ コレクションにより収集される前に、その Objectのリソースを解放し、その他のクリーンアップ操作を実行できるようにするメソッドです。 オーバーライドされたDisposeを実行します。 GC.SuppressFinalizeメソッドで、 指定したオブジェクトに対して、ファイナライザを呼び出さないことをシステムに要求します メンバ変数myDisposeがFalseならmyDisposeをTrueで初期化します。 OnRender メソッドは、DrawingContext 型のオブジェクトを使用して呼び出されます。これは、DrawText などの描画メソッドの完全なセットを定義するクラスです。 Dictionaryジェネリック型のtrackedSkeletonsの値の中を、スケルトンの追跡者であるfaceInformation変数で反復処理しながら、顔を三角形で描画する処理を行います。参照の追加
C:\Program Files\Microsoft SDKs\Kinect\Developer Toolkit v1.5.1\Samples\bin\
に存在しますので、これを指定してください。
「C:\Program Files\Microsoft SDKs\Kinect\Developer Toolkit v1.5.1\Redist\x86\フォルダ内のFaceTrackData.dllとFaceTrackLib.dllを、作成したプロジェクトのbin\Debugフォルダ内に手動でコピーする」
この手続きを行っていないと、筆者の環境では「コピーできません」というエラーが発生しました。エラーが出ない場合はこの作業は不要です。ユーザーコントロールのロジックコードを記述する
リスト2 (FaceTrackingViewer.xaml.vb)
Option Strict On
Imports Microsoft.Kinect
Imports Microsoft.Kinect.Toolkit
Imports Microsoft.Kinect.Toolkit.FaceTracking
Public Class FaceTrackingViewer
Public Shared ReadOnly KinectProperty As DependencyProperty = DependencyProperty.Register("Kinect", GetType(KinectSensor), GetType(FaceTrackingViewer), New PropertyMetadata(Nothing, Sub(o, args)
DirectCast(o, FaceTrackingViewer).OnSensorChanged(DirectCast(args.OldValue, KinectSensor), DirectCast(args.NewValue, KinectSensor))
End Sub))
Const MaxMissedFrames As UInteger = 100
Dim trackedSkeletons As New Dictionary(Of Integer, SkeletonFaceTracker)()
Dim myColorImage As Byte()
Dim myColorImageFormat As ColorImageFormat = ColorImageFormat.Undefined
Dim myDepthImage As Short()
Dim myDepthImageFormat As DepthImageFormat = depthImageFormat.Undefined
Dim myDisposed As Boolean
Dim skeletonData As Skeleton()
SkeletonFaceTrackerクラスを定義します。
Private Class SkeletonFaceTracker
Shared faceTriangles As FaceTriangle()
Dim facePoints As EnumIndexableCollection(Of FeaturePoint, PointF)
Dim myFaceTracker As FaceTracker
Dim lastFaceTrackSucceeded As Boolean
Dim mySkeletonTrackingState As SkeletonTrackingState
Property LastTrackedFrame As Integer
全てのリソースを解放するDisposeメソッド
Public Sub Dispose()
If myFaceTracker Is Nothing = False Then
myFaceTracker.Dispose()
myFaceTracker = Nothing
End If
End Sub
顔を三角形の集合体で描画する処理
反復変数iで、特徴点と2 次元平面に点を定義する浮動小数点座標ペア(x 座標と y 座標)を表す型を持つ、EnumIndexableCollectionクラス型の変数facePointsで顔の座標を取得し、その個数をCountプロパティで取得して、個数分反復処理を行います。変数iに対応する、取得した顔のxとy座標をAddメソッドで、System.Windows.Point型のリストであるfaceModelPtsオブジェクトに追加していきます。 Public Sub DrawFaceModel(drawingContext As DrawingContext)
If lastFaceTrackSucceeded = False OrElse mySkeletonTrackingState <> SkeletonTrackingState.Tracked Then
Return
End If
Dim faceModelPts = New List(Of System.Windows.Point)()
Dim faceModel = New List(Of FaceModelTriangle)()
For i As Integer = 0 To facePoints.Count - 1
faceModelPts.Add(New System.Windows.Point(CInt(Me.facePoints(i).X), CInt(Me.facePoints(i).Y)))
Next
For Each t In faceTriangles
Dim triangle = New FaceModelTriangle()
triangle.P1 = faceModelPts(t.First)
triangle.P2 = faceModelPts(t.Second)
triangle.P3 = faceModelPts(t.Third)
faceModel.Add(triangle)
Next
Dim faceModelGroup = New GeometryGroup()
For i As Integer = 0 To faceModel.Count - 1
Dim faceTriangle = New GeometryGroup()
faceTriangle.Children.Add(New LineGeometry(faceModel(i).P1, faceModel(i).P2))
faceTriangle.Children.Add(New LineGeometry(faceModel(i).P2, faceModel(i).P3))
faceTriangle.Children.Add(New LineGeometry(faceModel(i).P3, faceModel(i).P1))
faceModelGroup.Children.Add(faceTriangle)
Next
drawingContext.DrawGeometry(Brushes.Red, New Pen(Brushes.Red, 2.0), faceModelGroup)
End Sub
顔の追跡情報を更新する処理
Friend Sub OnFrameReady(kinect As KinectSensor, myColorImageFormat As ColorImageFormat, myColorImage As Byte(), myDepthImageFormat As DepthImageFormat, myDepthImage As Short(), mySkeleton As Skeleton)
mySkeletonTrackingState = mySkeleton.TrackingState
If mySkeletonTrackingState <> SkeletonTrackingState.Tracked Then
Return
End If
If myFaceTracker Is Nothing = True Then
Try
myFaceTracker = New FaceTracker(kinect)
Catch generatedExceptionName As InvalidOperationException
myFaceTracker = Nothing
End Try
End If
If myFaceTracker Is Nothing = False Then
Dim frame As FaceTrackFrame = myFaceTracker.Track(myColorImageFormat, myColorImage, myDepthImageFormat, myDepthImage, mySkeleton)
lastFaceTrackSucceeded = frame.TrackSuccessful
If lastFaceTrackSucceeded = True Then
If faceTriangles Is Nothing = True Then
faceTriangles = frame.GetTriangles()
End If
facePoints = frame.GetProjected3DShape()
End If
End If
End Sub
FaceModelTriangle構造体の定義
Private Structure FaceModelTriangle
Public P1 As System.Windows.Point
Public P2 As System.Windows.Point
Public P3 As System.Windows.Point
End Structure
End Class
Finalizeをオーバーライドします。
Protected Overrides Sub Finalize()
Try
Dispose(False)
Finally
MyBase.Finalize()
End Try
End Sub
KinectSensor型のプロパティKinectを定義しておきます。
Public Property Kinect() As KinectSensor
Get
Return DirectCast(Me.GetValue(KinectProperty), KinectSensor)
End Get
Set(value As KinectSensor)
Me.SetValue(KinectProperty, value)
End Set
End Property
全てのリソースを解放するDisposeメソッド
Public Sub Dispose()
Me.Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Disposeメソッドをオーバーライドする処理
Protected Overridable Sub Dispose(disposing As Boolean)
If myDisposed = False Then
myDisposed = True
End If
End Sub
OnRenderメソッドをオーバーライドする処理
Protected Overrides Sub OnRender(drawingContext As DrawingContext)
MyBase.OnRender(drawingContext)
For Each faceInformation As SkeletonFaceTracker In trackedSkeletons.Values
faceInformation.DrawFaceModel(drawingContext)
Next
End Sub
顔の動きを追跡するKinectサンプル
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- 人物を切り抜いて画面に表示するKinectサンプル
- 人物特定に使える!?実際の映像で顔を認識するKinectプログラム
- Kinectで人体を認識して棒人間を動かすサンプル
- Kinectを使って、自分の手のひらに小さな分身を出現させてみる
- プレイヤーの身体パーツを判別するKinectサンプル
- Kinectで手の動きに合わせてモニタ上の画像を動かすサンプル
- Kinectで結成したマイ・ダンスチームを、サンプルを見ながら実際の背景に合成してみよう
- Kinectの音声認識を使って、プレイヤーを分離、結合させるデモを試してみる
- これであなたもダンスグループの一員!?Kinectで自分を分身させるプログラムを作る
- 人体の連続した動作を音声でキャプチャするKinectのサンプルプログラム