声で選んだアイテムをプレイヤーの身体に装着・連動させるKinectサンプル

2012年7月26日(木)
薬師寺 国安

前ページからの続きです。

ウィンドウが読み込まれた時の処理

Kinectが接続されているかどうかを確認します。
Choicesクラスは、要素を構成するための代替項目の一覧を表すクラスで、GrammarBuilder オブジェクトからのみ直接使用されます。認識させる言葉をAddメソッドで登録します。
GrammarBuilderクラスは、単純な入力から複雑な Grammar(構文情報を取得管理するクラス)を構築するためのメカニズムを提供するクラスで、登録された言葉の構文(文法)設定を行い、SpeechRecognitionEngineへと設定します。
Appendメソッドで、登録した言葉を GrammarBuilder オブジェクトとして現在の GrammarBuilder に追加します。

文法のチェックされた言葉(builder)で初期化された、新しいGrammerクラスのインスタンス、myGrammerオブジェクトを作成します。
Grammerクラスは、構文情報を取得および管理するためにランタイムをサポートするクラスです。

SpeechRecognitionEngineクラスの新しいインスタンスengineオブジェクトを作成します。

SpeechRecognitionEngineクラスのLoadGrammerメソッドで、Grammar によって指定されたとおりに、特定の構文を同期的に読み込みます。

Kinectを開始します。Kinectの音声インターフェースは、Kinect.AudioSourceで提供されます。
Startメソッドで音声入力を開始します。

入力ストリームを取得し、SpeechRecognitionEngine クラスのSetInputToDefaultAudioDeviceメソッドで、SpeechRecognitionEngine の現在のインスタンスに、システム既定のオーディオ入力を割り当てます。
複数の音声認識が可能なように、RecognizeMode.Multipleを指定して、RecognizeAsyncメソッドで非同期音声認識を開始します。

Kinectが接続されていない場合はメッセージを出して処理を抜けます。
RGBカメラ、距離カメラ、プレイヤーおよびスケルトンの認識を開始します。
AddHandlerステートメントで、RGBカメラ、距離カメラ、スケルトンのフレーム更新イベントが発生した場合のAllFramesReadyにkinect_AllFramesReadyイベントハンドラを追加します。

言葉が認識された際には、AddHandlerステートメントで言葉を認識した際に発生するSpeechRecognizedイベントに、イベントハンドラを指定します。
Confidenceプロパティで音声認識の信頼度を設定します。-1が低、0が標準、1が高信頼度となります。
この時、-1を指定するとどんな言葉でも反応する恐れがあります。1を指定するとなかなか認識してくれません。
今回は信頼度が0.5より大きい場合に言葉を認識するよう指定しています。

speechArgs.Result.Textで認識された音声を変数wordsに格納し、wordsの言葉で条件分岐を行います。

「マスク」と発声した場合は、XElement.Loadメソッドでface.xmlを読み込みます。FancyDressInfoクラス型の新しいリストであるmyFancyDressInfoを作成します。
Descendantsメソッドで、子孫要素である全ての 要素のコレクションに対して、各要素を変数resultに格納しながら、FancyDressInfo クラスの各プロパティに、result.Element(要素名).Value で要素の内容テキストを、result.Attribute(属性名).Valueで要素の属性”width”と”height”の値を指定し、AddメソッドでmyFancyDressInfoオブジェクトに追加していきます。
ListBox1のItemsSourceプロパティにmyFancyDressInfoオブジェクトを指定します。
ListBox1に「鬼」や「般若」の画像が表示されます。
ListBox1のSeletedIndexプロパティに「マスクアップ」「マスクダウン」という言葉で増減する変数noの値を指定しておきます。

「部品」と発声した場合は、XElement.Loadメソッドでgoods.xmlを読み込みます。
FancyDressInfoクラス型の新しいリストであるmyFancyDressInfoを作成します。

Descendantsメソッドで、子孫要素である全ての 要素のコレクションに対して、各要素を変数resultに格納していきます。
FancyDressInfo クラスの各プロパティに、result.Element(要素名).Value で要素の内容テキストを指定します。
result.Attribute(属性名).Valueで要素の属性”width”と”height”の値を指定します。
次に値の設定された各プロパティをAddメソッドでmyFancyDressInfoオブジェクトに追加していきます。

ListBox2のItemsSourceプロパティにmyFancyDressInfoオブジェクトを指定すると、ListBox2に「金棒」や「扇子」の画像が表示されます。
ListBox2のSeletedIndexプロパティに「部品アップ」「部品ダウン」という言葉で増減する変数no2の値を指定しておきます。

「マスクダウン」ではメンバ変数noの値を1ずつ増加します。
「マスクアップ」ではメンバ変数noの値を1ずつ減少します。
「部品ダウン」ではメンバ変数no2の値を1ずつ増加します。
「部品アップ」ではメンバ変数no2の値を1ずつ減少します。

「おわり」と発した場合はKinectの動作とオーディオや音声認識の動作を停止し、プログラムを終了します。

  Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    If KinectSensor.KinectSensors.Count > 0 Then
      kinect = KinectSensor.KinectSensors(0)
      kinect.Start()
    End If
 
    Dim sentence As Choices = New Choices
    With sentence
      .Add("マスク")
      .Add("マスクダウン")
      .Add("マスクアップ")
      .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)
      Dim confidence As Single = speechArgs.Result.Confidence
        If confidence > 0.5 Then
          words = speechArgs.Result.Text
            Select Case words
              Case "マスク"
                If ListBox1.Items.Count > 0 Then
                  Exit Sub
                Else
                xmldoc = XElement.Load("face.xml")
                Dim myFancyDressInfo As New List(Of FancyDressInfo)
              For Each result In From c In xmldoc.Descendants("name") Select c
                With myFancyDressInfo
                  .Add(New FancyDressInfo With {.name = "Image/" & result.Value, ._height = CInt(CDbl(result.Attribute("height").Value) / 1.8), ._width = CInt(CDbl(result.Attribute("width").Value) / 1.8)})
                End With
              Next
              ListBox1.ItemsSource = myFancyDressInfo
              ListBox1.SelectedIndex = no
            End If
 
            Case "部品"
              If ListBox2.Items.Count > 0 Then
                Exit Sub
              Else
                xmldoc = XElement.Load("goods.xml")
              Dim myFancyDressInfo As New List(Of FancyDressInfo)
              For Each result In From c In xmldoc.Descendants("name") Select c
                With myFancyDressInfo
                  .Add(New FancyDressInfo With {.name = "Image/" & result.Value, ._height = CDbl(result.Attribute("height").Value), ._width = CDbl(result.Attribute("width").Value)})
                End With
              Next
                ListBox2.ItemsSource = myFancyDressInfo
                ListBox2.SelectedIndex = no2
              End If
            Case "マスクダウン"
              If no >= ListBox1.Items.Count - 1 Then no = ListBox1.Items.Count - 1
              no = no + 1
              ListBox1.SelectedIndex = no
            Case "マスクアップ"
              If no <= 0 Then no = 0
              no = no - 1
              ListBox1.SelectedIndex = no
            Case "部品ダウン"
              If no2 >= ListBox2.Items.Count - 1 Then no2 = ListBox2.Items.Count - 1
                                      no2 = no2 + 1
                           ListBox2.SelectedIndex = no2
                         Case "部品アップ"
                           If no2 <= 0 Then no2 = 0
                           no2 = no2 - 1
                           ListBox2.SelectedIndex = no2
                         Case "おわり"
                           If kinect.IsRunning = True Then
                              kinect.Stop()
                              kinect.AudioSource.Stop()
                              engine.RecognizeAsyncStop()
                           End If
                              Environment.Exit(0)
                       Case Else
                              Exit Select
            End Select
          End If
              End Sub
 
    Dim audio As KinectAudioSource = kinect.AudioSource
    Using s As Stream = audio.Start()
      engine.SetInputToDefaultAudioDevice()
      engine.RecognizeAsync(RecognizeMode.Multiple)
    End Using
    Try
      If KinectSensor.KinectSensors.Count = 0 Then
        MessageBox.Show("Kinectを接続してください")
        Exit Sub
      Else
        kinect.ColorStream.Enable()
        kinect.DepthStream.Enable()
        kinect.SkeletonStream.Enable()
        AddHandler kinect.AllFramesReady, AddressOf kinect_AllFramesReady
      End If
    Catch ex As Exception
      MessageBox.Show(ex.Message)
      Close()
    End Try
  End Sub
  • 声でアイテムを選んで身体に装着・連動させる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 Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

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