PR

人体の連続した動作を音声でキャプチャするKinectのサンプルプログラム

2012年9月21日(金)
薬師寺 国安

ロジックコードを記述する

リスト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
Think IT会員限定特典
  • Kinectセンサーによる音声でのモーションキャプチャのサンプル

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think IT会員サービス無料登録受付中

Think ITでは、より付加価値の高いコンテンツを会員サービスとして提供しています。会員登録を済ませてThink ITのWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

他にもこの記事が読まれています