人体の連続した動作を音声でキャプチャするKinectのサンプルプログラム
ロジックコードを記述する
リスト2 (MainWindow.xaml.vb)
Option Strict On Imports Microsoft.Kinect Imports Microsoft.Speech.AudioFormat Imports Microsoft.Speech.Recognition Imports System.IO Imports System.Windows.Media.Imaging Class MainWindow
1個のKinectセンサーを表すメンバ変数Kinectを宣言します。
Dim Kinect As KinectSensor
整数四角形の幅、高さ、および位置を表すInt32Rect構造体のメンバ変数myScreenImageRectを宣言します。領域の指定に使用されます。
Dim myScreenImageRect As Int32Rect
Short型の配列メンバ変数myDepthPixelDataとByte型の配列メンバ変数myColorPixelDataを宣言しておきます。
※深度情報は、1ピクセルあたり2バイトのshort型。画像情報はフルカラーなので1ピクセルあたり4バイトのbyte型です。
Dim myDepthPixelData As Short() Dim myColorPixelData As Byte()
音声認識サービスを実行するためのアクセス権を提供するクラスである、SpeechRecognitionEngineクラス用メンバ変数engineを宣言します。
Dim engine As SpeechRecognitionEngine
作成される画像の個数を表すメンバ変数noを宣言します。
Dim no As Integer = 0
深度を指定する定数メンバ変数targetDepthを宣言し、2000(2m)で初期化しておきます。Kinectセンサーからの距離を2mとって動作確認をする必要があります。
Const targetDepth As Double=2000
Imageクラス型のmyImageメンバ変数を宣言します。
Dim myImage As Image
認識された言葉を格納するメンバ変数wordsを宣言します。
Dim words As String
WriteableBitmapクラス型のHuman1_bitmap、Human2_bitmap、Room_Bitmapプロパティを定義しておきます。
Property Human1_bitmap As WriteableBitmap Property Human2_bitmap As WriteableBitmap Property Room_Bitmap As WriteableBitmap
ウィンドウが読み込まれた時の処理
システムの特別なフォルダである「マイピクチャ」へのディレクトリパスを変数dirに格納します。「マイピクチャ」内に「KINECT_Separate」というサブフォルダがなかった場合は、CreateDirectoryメソッドで「KINECT_Separate」というサブフォルダを作成します。
Choicesクラスは、要素を構成するための代替項目の一覧を表すクラスで、GrammarBuilder オブジェクトからのみ直接使用されます。認識させる言葉をAddメソッドで登録します。
GrammarBuilderクラスは、単純な入力から複雑な Grammar(構文情報を取得管理するクラス)を構築するためのメカニズムを提供するクラスで、登録された言葉の構文(文法)設定を行い、SpeechRecognitionEngineへと設定します。Appendメソッドで、登録した言葉を GrammarBuilder オブジェクトとして現在の GrammarBuilder に追加します。
文法のチェックされた言葉(builder)で初期化された、新しいGrammerクラスのインスタンス、myGrammerオブジェクトを作成します。Grammerクラスは、構文情報を取得および管理するためにランタイムをサポートするクラスです。
次に、SpeechRecognitionEngineクラスの新しいインスタンスengineオブジェクトを作成します。
SpeechRecognitionEngineクラスのLoadGrammerメソッドで、Grammar によって指定された通りに、特定の構文を同期的に読み込みます。
Kinectセンサーを取得し、Kinectセンサーを動作させます。Kinectの音声インターフェースは、Kinect.AudioSourceで提供されます。Startメソッドで音声入力を開始します。入力ストリームを取得し、SpeechRecognitionEngine クラスのSetInputToDefaultAudioDeviceメソッドで、SpeechRecognitionEngine の現在のインスタンスに、システム既定のオーディオ入力を割り当てます。
認識操作の後に、RecognizeAsync によって開始された認識を終了しないよう、RecognizeMode.Multipleを指定して、RecognizeAsyncメソッドで非同期音声認識を開始します。
言葉が認識されたら、AddHandlerステートメントで言葉を認識した際に発生するSpeechRecognizedイベントに、イベントハンドラを指定します。認識された音声(speechArgs.Result.Text)を変数wordsに格納します。Confidenceプロパティで音声認識の信頼度を設定します。-1が低、0が標準、1が高信頼度となります。-1を指定するとどんな言葉にでも反応する恐れがあります。1を指定するとなかなか認識してくれません。今回は信頼度が0.5より大きい場合に設定しています。
ここでは、「わかれる」と発声された場合の処理は不要です。「わかれる」と発声した場合の処理は、CompositionTarget.Renderingイベント内で行います。
「くっつく」と発声された場合は、personImageというCanvas内をクリアします。メンバ変数noを0で初期化します
「おわり」と発声された場合はKinectセンサーの動作を停止し、音声認識も停止し、Environment.Exit(0)でプログラムを終了します。
RGBカメラ、距離カメラ、スケルトンを有効にし、各画像データを初期化するinit_kinectプロシージャを実行します。
構成ツリーのオブジェクトがレンダリングされる直前に発生する、CompositionTarget.Renderingイベントにイベントハンドラを指定します。イベントハンドラ内では以下の処理を行います。
OpenNextFrame(100)メソッドで、KinectからRGBデータの次のフレームを開きます。次のフレームがなかった場合のタイムアウトを100ミリセコンドと指定しています。同様に、Kinectから深度データの次のフレームを開きます。次のフレームがなかった場合のタイムアウトを100ミリセコンドと指定しています。
背景を描画し距離データを取得するRenderScreenプロシージャを実行します。引数として、Kinectのストリーミング用RGBデータのバッファと深度データのバッファを含んでいる、colorFrameとdepthFrameを渡しています。
「わかれる」と発声された場合は、プレイヤーの動作を保存するSeparateHumanプロシージャを実行します。「中止」と発声された場合は、depthFrameオブジェクトのリソースを解放します。DataContextプロパティにMainWindow自身のインスタンスを指定します。この処理を行わないとプレイヤーが表示されませんので注意してください。
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_Separate")) = False Then Directory.CreateDirectory(Path.Combine(dir, "KINECT_Separate")) End If If KinectSensor.KinectSensors.Count = 0 Then MessageBox.Show("Kinectが接続されておりません。") Exit Sub End If Dim sentence As Choices = New Choices With sentence .Add("わかれる") .Add("中止") .Add("くっつく") .Add("おわり") End With Dim builder As GrammarBuilder = New GrammarBuilder builder.Append(sentence) Dim myGrammer As Grammar = New Grammar(builder) engine = New SpeechRecognitionEngine engine.LoadGrammar(myGrammer) AddHandler engine.SpeechRecognized, Sub(speechSender As Object, speechArgs As SpeechRecognizedEventArgs) Try words = speechArgs.Result.Text Dim confidence = speechArgs.Result.Confidence If confidence > 0.5 Then Select Case words Case "くっつく" personImage.Children.Clear() no = 0 Case "おわり" personImage.Children.Clear() If Kinect Is Nothing = False Then If Kinect.IsRunning = True Then Kinect.Stop() Kinect.AudioSource.Stop() engine.RecognizeAsyncStop() Kinect.Dispose() End If End If Environment.Exit(0) End Select End If Catch Exit Sub End Try End Sub Kinect = KinectSensor.KinectSensors(0) Kinect.Start() Dim audio As KinectAudioSource = Kinect.AudioSource Using s As Stream = audio.Start() engine.SetInputToDefaultAudioDevice() engine.RecognizeAsync(RecognizeMode.Multiple) End Using targetDepth = 2000 init_kinect() AddHandler CompositionTarget.Rendering, Sub(renderSender As Object, renderArgs As EventArgs) Using colorFrame As ColorImageFrame = Kinect.ColorStream.OpenNextFrame(100) Using depthFrame As DepthImageFrame = Kinect.DepthStream.OpenNextFrame(100) RenderScreen(colorFrame, depthFrame) If words = "わかれる" Then SeparateHuman() ElseIf words = "中止" Then depthFrame.Dispose() End If End Using End Using End Sub DataContext = Me End Sub
プレイヤーの動作を保存する処理
「わかれる」と発声された場合は、システムの特別なフォルダである「マイピクチャ」へのディレクトリパスを変数dirに格納しておきます。「マイピクチャ」内の「KINECT_Separate」サブフォルダへのディレクトリパスを変数saveDirに格納します。
BitmapFrameクラスのbmpFrame変数を宣言します。BitmapFrameクラスは、デコーダによって返されてエンコーダによって受け入れられるイメージ データを表すクラスです。
BitmapFrame.CreateメソッドでHuman2_bitmapプロパティからBitmapFrameを作成します。1ずつ加算されるメンバ変数noと、文字列dummyと.pngを連結したファイル名と、新規作成モードで指定した形式で初期化された、FileStreamのインスタンスstreamオブジェクトを作成します。
新しいPngBitmapEncoderクラスのインスタンスmyPngオブジェクトを作成します。PngBitmapEncodeクラスは、PNG形式のイメージのエンコードに使用されるエンコーダを定義するクラスです。
myPngオブジェクトのイメージ内の個別のフレームに、Addメソッドで作成した画像ファイルを追加していきます。SaveメソッドでHuman2_bitmapを「マイピクチャ」の「KINECT_Separate」サブフォルダ内に保存します。ファイル名はdummy0.png、dummy1.png・・・・・dummy50.pngといった形式になります。保存される画像はPNG形式で背景が透明化された画像になります。
新しいImageクラスのインスタンスmyImageオブジェクトを作成します。WidthとHeightプロパティを設定し、Sourceプロパティに、先ほど保存した「KINECT_Separate」サブフォルダ内の画像を指定します。この場合は必ずUriKind.Absoluteと指定し、絶対URIで指定します。personImageというCanvasに、AddメソッドでmyImageオブジェクトを追加します。メンバ変数noの値を1ずつ増加させると、保存されていた画像が順次表示されます。
Private Sub SeparateHuman() Dim dir As String = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) Dim saveDir As String = Path.Combine(Dir, "KINECT_Separate") Dim bmpFrame As BitmapFrame = BitmapFrame.Create(Human2_bitmap) Using stream As FileStream = New FileStream(Path.Combine(saveDir, "dummy" & no & ".png"), FileMode.Create) Dim myPng As PngBitmapEncoder = New PngBitmapEncoder myPng.Frames.Add(bmpFrame) myPng.Save(stream) End Using myImage = New Image With myImage .Width = 640 .Height = 480 .Source = New BitmapImage(New Uri(Path.Combine(saveDir, "dummy" & no & ".png"), UriKind.Absolute)) End With personImage.Children.Add(myImage) no = no + 1 End Sub
Kinectセンサーによる音声でのモーションキャプチャのサンプル
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Kinectを使って、画面上の赤い輪をくぐるサンプル
- Kinectを使って、自分の手のひらに小さな分身を出現させてみる
- Kinectで結成したマイ・ダンスチームを、サンプルを見ながら実際の背景に合成してみよう
- Kinectの音声認識を使って、プレイヤーを分離、結合させるデモを試してみる
- これであなたもダンスグループの一員!?Kinectで自分を分身させるプログラムを作る
- プレイヤーの身体パーツを判別するKinectサンプル
- Kinectで距離カメラの値を取得して、指定した距離で人物が背景に溶け込むサンプル
- 人物を切り抜いて画面に表示するKinectサンプル
- Kinectを使って、顔の動きを認識して画面に表示する
- 人物特定に使える!?実際の映像で顔を認識するKinectプログラム