Kinectを使った、音声によるデータ保存と検索のサンプル

2012年8月24日(金)
薬師寺 国安

参照の追加

VS2010のメニューから「プロジェクト(P)/参照の追加(R)」と選択して、各種コンポーネントを追加しておきます。今回追加するのは、Microsoft.KinectとMicrosoft.Speechの2つです。「.NET」タブ内に表示されていないDLLファイルは「参照」タブからDLLファイルを指定します。

Microsoft.Kinect.dllは、C:\Program Files\Microsoft SDKs\Kinect\v1.5\Assemblies内に存在しますので、これを指定します。

Microsoft.Speech.dllは
C:\Windows\assembly\GAC_MSIL\Microsoft.Speech\11.0.0.0__31bf3856ad364e35\に存在しますので、これを指定してください。このassemblyフォルダ内のGAC_MSILフォルダは「参照の追加(R)」の「参照」タブからでないと参照できません。
マイコンピューターからは、このフォルダは表示されませんので注意してください。

次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックして、リスト3のコードを記述します。

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

リスト3 (MainWindow.xaml.vb)

Option Strict On
Imports Microsoft.Kinect
Imports System.IO

音声認識を実装するためのクラスが含まれる、Microsoft.Speech.Recognition名前空間をインポートします。

Imports Microsoft.Speech.Recognition

音声認識用のオーディオ形式を表すクラスが含まれる、Microsoft.Speech.AudioFormat名前空間をインポートします。

Imports Microsoft.Speech.AudioFormat

Class MainWindow

一つのKinectセンサーを表すメンバ変数Kinectを宣言します。

  Dim Kinect As KinectSensor

XML要素を表すXElementクラス型のメンバ変数xmldocを宣言します。

  Dim xmldoc As XElement

音声認識サービスを実行するためのアクセス権を提供するSpeechRecognitionEngineクラス用メンバ変数engineを宣言します。

  Dim engine As SpeechRecognitionEngine

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

Kinectセンサーを開始し、音声認識を開始するDataShowプロシージャを実行します。

  Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    DataShow()
  End Sub

Kinectセンサーを開始し、音声認識を開始する処理

bin\Debugフォルダ内のPersonalInfo.xmlを読み込みます。
Kinectセンサーを開始し、音声認識を開始するcreateSpeechRecognizerプロシージャを実行します。

  Private Sub DataShow()
    xmldoc = XElement.Load("PersonalInfo.xml")
    If KinectSensor.KinectSensors.Count = 0 Then
      MessageBox.Show("KINECTが接続されておりません。")
      Exit Sub
    Else
      Kinect = KinectSensor.KinectSensors(0)
      Kinect.Start()
      createSpeechRecognizer()
    End If
  End Sub

認識させる言葉を登録し、音声認識を開始する処理

音声認識サービスを実行するためのアクセス権を提供する、SpeechRecognitionEngineクラスの新しいインスタンスengineオブジェクトを作成します。
要素を構成するための代替項目の一覧を表すChoicesクラスのインスタンス、sentenceオブジェクトを作成します。Choiceクラスは、GrammarBuilder オブジェクトからのみ直接使用されます。
Descendantsメソッドで、子孫要素であるすべての 要素のコレクションに対して、各要素を変数 result に格納しながら、以下の処理を繰り返します。

要素の値をAddメソッドで、認識させる言葉としてChoicesオブジェクトであるsentenceに追加します。また、Datain、Datasearch、Menu、Save、Continue、Endという語句も追加しておきます。

GrammarBuilderクラスは、単純な入力から複雑な Grammar(構文情報を取得管理するクラス)を構築するためのメカニズムを提供するクラスで、登録された言葉の構文(文法)設定を行い、SpeechRecognitionEngineへと設定します。
Appendメソッドで、登録した言葉を GrammarBuilder オブジェクトとして現在の GrammarBuilder に追加します。

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

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

言葉が認識された際には、AddHandlerステートメントで言葉を認識した際に発生するSpeechRecognizedイベントに、イベントハンドラを指定します。

Confidenceプロパティで音声認識の信頼度を設定します。-1が低、0が標準、1が高信頼度となります。-1を指定するとどんな言葉でも反応する恐れがあります。1を指定するとなかなか認識してくれません。今回は信頼度が0.3より大きい場合に、指定した言葉を認識するよう指定しています。

認識された音声(speechArgs.Result.Text)を変数myNameに格納します。myNameの内容で条件分岐を行います。XML文書の要素の子要素の値が、変数myNameの値と同じである、要素を選択するクエリを定義します。結果クエリの個数が0の場合は、「氏名」の入力ボックスに「該当なし」と表示し、処理を抜けます。

定義したクエリ内を変数resultで反復処理しながら、「データ検索画面(この時点では非表示)」の各TextBoxに、該当する要素の内容テキストを表示します。

「Datain」と発声された場合は、メニューと検索画面を非表示にし、「データ入力」画面だけを表示します。

「Datasearch」と発声された場合は、Kinectセンサーを開始し、音声認識を開始するDataShowプロシージャを実行します。要素の個数を取得し、データがない場合は処理を抜けます。データが存在する場合は、各検索結果を表示するTextBoxを空に初期化し、「検索画面」だけを表示します。

「Menu」と発声された時は、「Menu」画面だけを表示します。

「Save」と発声された場合は、「年齢」入力欄に入力された値が数値かどうかを判別して、数値以外であった場合は、「年齢」の入力ボックスにフォーカスを移し、警告メッセージを表示して、処理を抜けます。入力されたデータをXMLに保存するDataSaveプロシージャを実行します。

「Continue」と発声された場合は、メッセージを表示するTextBlock内を空にし、各入力ボックスを空で初期化し、「氏名」の入力ボックスにフォーカスを移します。

「End」と発声された場合は、Kinectセンサーを停止し、音声認識も停止して、Environment.Exit(0)でプログラムを終了します。

Kinectの音声インターフェースは、Kinect.AudioSourceで提供されます。Startメソッドで音声入力を開始します。入力ストリームを取得し、SpeechRecognitionEngine クラスのSetInputToDefaultAudioDeviceメソッドで、SpeechRecognitionEngine の現在のインスタンスに、システム既定のオーディオ入力を割り当てます。

認識操作の後に、RecognizeAsync によって開始された認識を終了しないよう、RecognizeMode.Multipleを指定して、RecognizeAsyncメソッドで非同期音声認識を開始します。

  Private Sub createSpeechRecognizer()
    engine = New SpeechRecognitionEngine()
      Dim sentence = New Choices()
    For Each result In From c In xmldoc.Descendants("情報") Select c
      sentence.Add(result.Element("氏名").Value)
    Next
    sentence.Add("Datain") 
    sentence.Add("Datasearch")
    sentence.Add("Menu")
    sentence.Add("Save")
    sentence.Add("Continue")
    sentence.Add("End")
 
    Dim myGrammerBuilder = New GrammarBuilder
    myGrammerBuilder.Append(sentence)
    Dim myGrammer = New Grammar(myGrammerBuilder)
    engine.LoadGrammar(myGrammer)
 
    AddHandler engine.SpeechRecognized, Sub(speechSender As Object, speechArgs As SpeechRecognizedEventArgs)
      Dim confidence As Single = speechArgs.Result.Confidence 
      If confidence > 0.3 Then
        Dim myName As String = speechArgs.Result.Text
        Select Case myName
          Case myName
            Dim query = From c In xmldoc.Descendants("情報") Where c.Element("氏名").Value.Equals(myName) Select c
              If query.Count = 0 Then
                searchNameTextBox.Text = "該当なし"
              End If
              For Each result In query
                searchNameTextBox.Text = result.Element("氏名").Value
                searchAgeTextBox.Text = result.Element("年齢").Value
                searchAddressTextBox.Text = result.Element("住所").Value
                searchCompanyTextBox.Text = result.Element("勤務先").Value
              Next
              If myName = "Datain" Then
                DataIn.Visibility = Windows.Visibility.Visible
                myStackPanel.Visibility = Windows.Visibility.Collapsed
                DataSearch.Visibility = Windows.Visibility.Collapsed
              End If
 
              If myName = "Datasearch" Then
                DataShow()
                Dim myCountQuery = From c In xmldoc.Descendants("情報") Select c
  
                If myCountQuery.Count <= 0 Then
                  Exit Sub
                Else
                  messageTextBlock.Text = String.Empty
                  searchNameTextBox.Text = String.Empty
                  searchAgeTextBox.Text = String.Empty
                  searchAddressTextBox.Text = String.Empty
                  searchCompanyTextBox.Text = String.Empty
                  myStackPanel.Visibility = Windows.Visibility.Collapsed
                  DataIn.Visibility = Windows.Visibility.Collapsed
                  DataSearch.Visibility = Windows.Visibility.Visible
                End If
              End If
                If myName = "Menu" Then
                  DataIn.Visibility = Windows.Visibility.Collapsed
                  DataSearch.Visibility = Windows.Visibility.Collapsed
                  myStackPanel.Visibility = Windows.Visibility.Visible
                End If
              
                If myName = "Save" Then
                  Try
                    Dim myError As Integer = System.Convert.ToInt16(ageTextBox.Text, 10)
                  Catch ex As Exception
                    ageTextBox.Focus()
                    messageTextBlock.Text = "年齢が不正です。"
                    Exit Sub
                  End Try
                    DataSave()
                  End If
 
                  If myName = "Continue" Then
                    messageTextBlock.Text = String.Empty
                    nameTextBox.Text = String.Empty
                    ageTextBox.Text = String.Empty
                    addressTextBox.Text = String.Empty
                    companyTextBox.Text = String.Empty
                    nameTextBox.Focus()
                  End If
 
                  If myName = "End" Then
                    If Kinect.IsRunning = True Then
                      Kinect.Stop()
                          Kinect.AudioSource.Stop()
                          Environment.Exit(0)
                        End If
                      End If
                    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
  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メルマガ会員のサービス内容を見る

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