NtKinect: Kinect V2 C++ Programming with OpenCV on Windows10

Kinect V2 で音声を認識する


2016.07.18: created by
2016.07.31: revised by
2016.09.13: revised by
2019.08.31: revised by
Japanese English

本項目を読んだ後に「 NtKinect: Kinect V2 を用いた音声認識をDLL化してUnityから利用する 」を読んで、UnityからKinect V2の音声認識を使ってみることをお勧めします。

目次へ

前提として理解しておくべき知識


[注意] (2019/08/31 追記) コンパイル環境として Visual Studio 2019 や Visual Studio 2017 (後期バージョン)を用いると、 以下のエラーが出てコンパイルできません。

エラー  C2440  '既定の引数': 'const wchar_t [1]' から 'BSTR' に変換できません。 KinectV2C:\Program Files\Microsoft SDKs\Speech\v11.0\Include\sapi.h   12519
これは文字列リテラルの扱いが厳密になったためで /Zc:strictStrings- (文字列リテラル型の変換の無効化)オプションを付けてコンパイルすると、正常にコンパイルできます。
コンパイルオプションの設定方法
「ソリューションエクスプローラ」 -> プロジェクト名(KinectV2)上で右ドラッグ  -> プロパティ -> 構成プロパティ -> C/C++ -> コマンドライン -> 追加のオプション -> /Zc:strictStrings-


音声を認識するための前提条件

Kinect V2で音声認識を行うには次の設定が必要です。 特に、システムのどこかにある別の sapi.h をincludeしてプログラムが正しく動作しない 例が非常に多いのでVisual Studio のプロジェクトの設定には注意して下さい。

音声を認識する

USE_SPEECH 定数を define してから NtKinect.h を include する と NtKinect の音声認識関係のメソッドや変数が有効になります。

  #define USE_SPEECH
  #include "NtKinect.h"
  ...
NtKinect

NtKinect の音声認識に関するメソッド

返り値の型 メソッド名 説明
void setSpeechLang(string& lang , wstring& grxml ) 認識する言語をlang に、単語ファイル名を grxml に指定する。
デフォルトではそれぞれ "ja-JP" と L"Grammar_jaJP.grxml" に設定されている。
void startSpeech() 音声認識を開始する。
void stopSpeech() 音声認識を停止する。
bool setSpeech() 音声認識が開始された状態で呼ばれると、直近の音声データに対して音声認識を試み、以下のメンバ変数の値を設定する。
変数名説明
bool recognizedSpeech音声認識ができたかを表すフラグ
wstring speechTag音声認識の結果のタグ
wstring speechItem音声認識の結果の項目
float speechConfidence音声認識の結果の信頼度
NtKinect

NtKinect の音声認識に関するメンバ変数

変数名 説明
bool recognizedSpeech 音声認識ができたかを表すフラグ。
speechConfidenceがspeechThreshold以上だとtrueになる。
wstring speechTag 音声を認識できた場合に、その単語の「タグ」が設定される。
この「タグ」とは grxml ファイル中の tag タグで指定した値である。
wstring speechItem 音声認識ができた場合、その単語の「項目」が設定される。
この「項目」とは grxml ファイル中の item タグで指定した値である。
float speechConfidence 音声を認識した結果の信頼度。この値がconfidenceThresholdよりも大きいと音声を認識できたと判断される。
float confidenceThreshold 音声認識できたとみなす閾値。代入により値を設定できる。デフォルト値は0.3。

プログラム作成の手順

  1. KinectV2の音声認識SDK "Speech Platform SDK v11"をインストールします。
  2. http://www.microsoft.com/en-us/download/details.aspx?id=27226
    64bit版
      x64_MicrosoftSpeechPlatformSDK\MicrosoftSpeechPlatformSDK.msi
    



    ダウンロードした msi ファイルをクリックして、インストールします。


  3. さらに Speech SDK の Runtimeをインストールします。
  4. SpeechSDK のインストールによってできた、次の msi ファイルをクリックして実行します。

    C:\Program Files\Windows\SDKs\Speech\v11.0\Redist\SpeechPlatformRuntime.msi
    




  5. 言語ごとに用意されている音響モデルをダウンロードしてインストールします。
  6. http://www.microsoft.com/en-us/download/details.aspx?id=43662
       MSKinectLangPack_enUS.msi  英語
       MSKinectLangPack_jaJP.msi  日本語
    






    ダウンロードした2つの msi ファイルをクリックして実行します。

  7. 「SpeechSDK そのもの」と「SpeechSDKの Runtime」, および KinectLangPack の「英語音響モデル」と「日本語音響モデル」を インストールしたら、Windowsを再起動して下さい。
  8. 必要ないかもしれませんが、念のためです。

  9. NtKinect: Kinect V2 で音声を取得する。」 の Visual Studio のプロジェクト KinectV2_audio.zipを用いて作成します。
  10. WaveFile.hは既にプロジェクトに追加されているはずです。

  11. 認識させたい単語を記述したファイルを言語ごとに用意します。
  12. 今回認識させるのは日本語ですが、将来英語を認識させるように変更する場合を考えて、 どちらのファイルもプロジェクトに追加しましょう。

    US英語(usEN)用ファイルGrammar_enUS.grxml
    日本語(jaJP)用ファイルGrammar_jaJP.grxml

    まず grxml ファイルをプロジェクトのソースフォルダ(この例だと KinectV2_speech/KinectV2/ )に置きます。 それから「ソリューションエクスプローラー」の「リソースファイル」に右クリックで「追加」から「既存の項目」 を選びます。




    これらのファイルを編集したときは、UTF-8 で保存するようにしましょう。 文法の仕様は https://www.w3.org/TR/speech-grammar/ を参照して下さい。

  13. KinectAudioStream.hKinectAudioStream.cpp をプロジェクトに追加します。
  14. まず KinectAudioStream.h と KinectAudioStream.cpp をプロジェクトのソースフォルダ (この例だと KinectV2_speech/KinectV2/ )に置きます。 それから「ソリューションエクスプローラー」の「リソースファイル」に右クリックで 「追加」から「既存の項目」を選びます。







  15. プロジェクトの設定を変更します。
  16. 「ソリューションエクスプローラー」から「プロジェクト名(ここでは KinectV2)」の上で右クリックしてメニューから 「プロパティ」を選びます。




    構成プロパティ -> VC++ディレクトリで 「インクルードディレクトリ」の一番先頭に

    $(ProgramW6432)\Microsoft SDKs\Speech\v11.0\Include;
    
    を、「ライブラリディレクトリ」の一番先頭に
    $(ProgramW6432)\Microsoft SDKs\Speech\v11.0\Lib;
    
    を追加します。







    プロジェクトのプロパティの設定で 構成プロパティ -> リンカー -> 入力 -> 追加の依存ファイル -> sapi.libを追加します。




  17. main.cppの内容を以下のように変更します。
  18. NtKinect.hをincludeする前に USE_SPEECH 定数をdefineします。

    音声認識のプログラムはマルチスレッドで動作するので、 プログラムの最初で CoInitializeEx(NULL, COINIT_MULTITHREADED) を、最後で CoUninitialize() を実行します。

    Microsoft の Speech SDK によって音声を認識した結果は wchar_t で得られるので、 NtKinect でも結果は wstring で保持しています。 wstring ですので cout にはそのままでは書けませんのでこの例では wcout に出力しています。 wcout はlocale を設定しないとうまく動かないので注意が必要です。

        std::wcout.imbue(std::locale(""));   // locale 設定
    
    wstringのリテラルは L"EXIT" のようにダブルクォートの前に L がつくことに注意して下さい。 また、cout と wcout を混ぜて使うとよくないので避けて下さい。

    kinectに重い処理をさせると音声の取り込みが断続的になり、音声の認識がうまくできなくなります。 そこで、この例ではkinectの他のセンサや、ウィンドウ処理を省略しています。

    コンソール画面でのキーボード入力をリアルタイムで判断するために conio.h をincludeして _kbhit(), _getch() 関数を利用しています。

    main.cpp
    #include <iostream>
    #include <sstream>
    
    #include <conio.h>
    
    #define USE_SPEECH
    #include "NtKinect.h"
    
    using namespace std;
    
    void doJob() {
      NtKinect kinect;
      kinect.startSpeech();
      std::wcout.imbue(std::locale(""));
      while (1) {
        kinect.setSpeech();
        if (kinect.recognizedSpeech) {
          wcout << kinect.speechTag << L" " << kinect.speechItem << endl;
        }
        if (kinect.speechTag == L"EXIT") break;
        if (_kbhit() && _getch() == 'q') break;
      }
      kinect.stopSpeech();
    }
    
    int main(int argc, char** argv) {
      try {
        ERROR_CHECK(CoInitializeEx(NULL, COINIT_MULTITHREADED));
        doJob();
        CoUninitialize();
      } catch (exception &ex) {
        cout << ex.what() << endl;
        string s;
        cin >> s;
      }
      return 0;
    }
    
  19. プログラムを実行するとコンソールウィンドウが表示されます。'q' キーで終了します。
  20. 音声認識の結果は、コンソールに出力されます。 現在のgrxml では「赤」、「赤色」、「青」、「青色」、「緑」、「緑色」、「終了」、「終わり」が 単語として登録されています。 「終了」または「終わり」を音声認識するとプログラムは終了します。




    Grammar_jaJP.grxml
    <?xml version="1.0" encoding="utf-8" ?>
    <grammar version="1.0" xml:lang="ja-JP" root="rootRule" tag-format="semantics/1.0-literals" xmlns="http://www.w3.org/2001/06/grammar">
      <rule id="rootRule">
        <one-of>
          <item>
            <tag>RED</tag>
            <one-of>
              <item> 赤 </item>
              <item> 赤色 </item>
            </one-of>
          </item>
          <item>
            <tag>GREEN</tag>
            <one-of>
              <item> 緑 </item>
              <item> 緑色 </item>
            </one-of>
          </item>
          <item>
            <tag>BLUE</tag>
            <one-of>
              <item> 青 </item>
              <item> 青色 </item>
            </one-of>
          </item>
          <item>
            <tag>EXIT</tag>
            <one-of>
              <item> 終わり </item>
              <item> 終了 </item>
            </one-of>
          </item>
        </one-of>
      </rule>
    </grammar>
    
  21. サンプルのプロジェクトはこちら KinectV2_speech.zip
  22. 上記のzipファイルには必ずしも最新の NtKinect.h が含まれていない場合があるので、 こちらから最新版をダウンロードして 差し替えてお使い下さい。

  23. 試してみよう。
  24. 現在は閾値が0.3ですが、これを下げて 0.1 などにして誤認識がどう増えるか確認して下さい。

    また、認識言語を英語に変更してみましょう。

        NtKinect kinect;
        kinect.setSpeechLang("en-US", L"Grammar_enUS.grxml");   // <--これを追加すると英語になる
        kinect.startSpeech();
    
    Grammar_enUS.grxml
    <?xml version="1.0" encoding="utf-8" ?>
    <grammar version="1.0" xml:lang="en-US" root="rootRule" tag-format="semantics/1.0-literals" xmlns="http://www.w3.org/2001/06/grammar">
      <rule id="rootRule">
        <one-of>
          <item>
            <tag>RED</tag>
            <one-of>
              <item> Red </item>
            </one-of>
          </item>
          <item>
            <tag>GREEN</tag>
            <one-of>
              <item> Green </item>
            </one-of>
          </item>
          <item>
            <tag>BLUE</tag>
            <one-of>
              <item> Blue </item>
            </one-of>
          </item>
          <item>
            <tag>EXIT</tag>
            <one-of>
              <item> Exit </item>
              <item> Quit </item>
              <item> Stop </item>
            </one-of>
          </item>
        </one-of>
      </rule>
    </grammar>
    
  25. UnityでKinect V2の音声認識を使ってみましょう。 解説は こちら をご覧下さい。


http://nw.tsuda.ac.jp/