凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

Julius で音声認識させてみた

はじめに

前回、iRemocon を操作するところまでやりました(中身はただの telnet みたいなもんですが…)。
次はマイクで喋った言葉を拾ってそれに従って操作を出来るようにしようと思います。このエントリでは音声認識した結果を C++ で取ってくるところまでやります。
で、フリーの音声認識エンジンがないかと探してみたところ、Julius に白羽の矢が立ちました。

音声認識分野の界隈では有名らしいですが、分からない点が多かったのでぼやいてたら、色々な方に助言をいただいて、何とか動かすことができました。ありがとうございます!

環境

  • Ubuntu 11.10
  • Julius 4.2.1
  • gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)
  • Boost 1.48.0

Juliusのインストールと動作テスト

ここらが参考になりました。精度をちょっとだけ上げたかったので configure のオプションを付けておきました。

cvs -z3 -d:pserver:anonymous@cvs.sourceforge.jp:/cvsroot/julius co julius4
cd julius4
./configure --enable-setup
make

取りあえずこれでコンパイル完了。configure のオプションはもっといじれば、精度が良くなるかもしれません。
次に以下のページからディクテーションキットを落としてきて解凍します。

出来た fast.jconf だけさっきの julius のフォルダに突っ込んでおきます。

./julius/julius -C fast.jconf -input mic -charconv EUC-JP UTF-8

これで起動すると、

<<< please speak >>>

と聞かれるので喋れば認識した結果が表示されます。

pass1_best: テレビをつけて、 
sentence1: テレビをつけて。

Juliusをサーバモードで動かす

 -module オプションを付けて julius を起動するとサーバモードで立ち上がって、後は 10500 ポートと TCP/IP で通信すれば結果が XML で返ってきます。これをパースすれば所望の結果が得られるわけです。

サーバ側
./julius/julius -C fast.jconf -input mic -charconv EUC-JP UTF-8 -module
クライアント側
hecomi@hecominote:~/Program/cpp/iRemocon$ telnet 192.168.0.10 10500
Trying 192.168.0.10...
Connected to 192.168.0.10.
Escape character is '^]'.
<STARTPROC/>
.
<INPUT STATUS="LISTEN" TIME="1326295699"/>
.
<INPUT STATUS="STARTREC" TIME="1326295701"/>
.
<STARTRECOG/>
.
<INPUT STATUS="ENDREC" TIME="1326295703"/>
.
<ENDRECOG/>
.
<INPUTPARAM FRAMES="140" MSEC="1400"/>
.
<RECOGOUT>
  <SHYPO RANK="1" SCORE="-3549.973877">
    <WHYPO WORD="" CLASSID="<s>" PHONE="silB" CM="0.914"/>
    <WHYPO WORD="元気" CLASSID="元気:ゲンキ:元気:509" PHONE="g e N k i" CM="0.410"/>
    <WHYPO WORD="" CLASSID=":::63" PHONE="o" CM="0.928"/>
    <WHYPO WORD="つけ" CLASSID="つけ:ツケ:つける:239" PHONE="ts u k e" CM="0.468"/>
    <WHYPO WORD="" CLASSID=":::68" PHONE="t e" CM="0.638"/>
    <WHYPO WORD="" CLASSID=":::8" PHONE="sp" CM="0.546"/>
    <WHYPO WORD="" CLASSID="</s>" PHONE="silE" CM="1.000"/>
  </SHYPO>
</RECOGOUT>
.
<INPUT STATUS="LISTEN" TIME="1326295703"/>
.
Connection closed by foreign host.

うーん…、電気をつけて欲しかったんだけど…。
滑舌が悪いのかもしれないですが、まぁまぁ認識してくれます。

C++ で文字列に変換

次のようなプログラムをクライアントとして書きました。

コード
#include <iostream>
#include <boost/regex.hpp>
#include <boost/asio.hpp>

int main(int argc, char const* argv[])
{
        using namespace boost::asio;
        using namespace std;

        // Julius の ip と port を指定
        const std::string ip = "192.168.0.10";
        const int port       = 10500;

        // Julius へ接続
        ip::address addr = ip::address::from_string(ip);
        ip::tcp::endpoint ep(addr, port);
        ip::tcp::iostream s(ep);

        // Julius サーバ 起動
        s << "STATUS\n" << std::flush;

        // 応答を解析する正規表現
        boost::regex r("WORD=\"([^\"]+)\"");
        boost::smatch m;

        // Julius からの応答を解析
        string line, word;
        while (getline(s, line)) {
                if (boost::regex_search(line, m, r))
                        word += m.str(1);
                else if (line.find("<RECOGOUT>") != npos)
                        word = "";
                else if (line.find("</RECOGOUT>") != npos)
                        cout << word << endl;
        }

        return 0;
}
コンパイル
g++-4.6 julius_client.cpp -o julius_client -lboost_system -lboost_thread -lpthread -lboost_regex
結果

サーバを動かした後実行してなにかしゃべってみます。

力をつけて。
営利を期して。
人気をつけて。
電気をつけて。
平均を期して。
りに放棄して。
体にも来て。
気に置きしている。
テレビを受け付ける。
研究。
元気を。
日記をつけて。
力をつけて。
A.をつけて。
い。
整備。
GET!
お気に入り。
うーん、元気をつけて。
う。
テレビをつけて。
勉強決して
電気を消す

結論

たまにしか成功しない(#^ω^)ビキビキ

あたりを頑張ると精度良くなるよ!との情報も頂いたので頑張ってみます。
次は得た音声認識結果を iRemocon に送るところを作りたいと思います。