2011年12月9日金曜日

KINECT SDK 音声認識


KINECT SDKのSpeechサンプルプログラムにちょっと手を加えてみました。
サンプルは音声認識だけですが、それだけでは面白くないので声で首ふりできるようにしてみました。
C#のプログラムは初めてなので少し変なところもあるかもしれないですが、動作は問題ないはず・・・・

環境は
Windows7 Ultimate 64bit

KINECT SDK Beta2

SpeechPlatform SDK 10.2
SpeechPlatform Runtime 10.2
Kinect for Windows Language Pack, version 0.9
上の3つはKINECT SDKのダウンロードページ左下のリンクからダウンロードできます。

Visual C# 2010 Express

以下はソースです。

-------------------------------------------------------------------------------




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Research.Kinect.Nui;        //追加
using Microsoft.Research.Kinect.Audio;      //追加
using Microsoft.Speech.Recognition;         //追加
using Microsoft.Speech.AudioFormat;         //追加


namespace SpeechElevation
{
    public partial class Program
    {
        static Runtime nui;
        static Camera cam;

        public static void Main(string[] args)
        {
            //初期化
            if (Runtime.Kinects.Count == 0)
            {
                return;
            }

            nui = Runtime.Kinects[0];
            nui.Initialize(RuntimeOptions.UseColor);
            cam = nui.NuiCamera;

            //カメラの位置を初期化
            CamInit();

            //オーディオソース
            using (var source = new KinectAudioSource())
            {
                source.FeatureMode = true;
                source.AutomaticGainControl = false;  //音声認識のときは必ずfalse
                source.SystemMode = SystemMode.OptibeamArrayOnly;

                //認識エンジンの選択
                RecognizerInfo ri = GetKinectRecognizer();

                if (ri == null)
                {
                    Console.WriteLine("認識エンジンが見つかりません。");
                    return;
                }

                Console.WriteLine("認識エンジン: {0}", ri.Name);

                //認識エンジンの準備
                using (var sre = new SpeechRecognitionEngine(ri.Id))
                {
                    //認識する語句の準備
                    var wd = new Choices();
                    wd.Add("init");
                    wd.Add("up");
                    wd.Add("down");
                    wd.Add("suihei");   //ローマ字も使える

                    var gb = new GrammarBuilder();
                    //GrammerBuilderのCultureと認識エンジンのCultureを合わせる
                    gb.Culture = ri.Culture;
                    gb.Append(wd);

                    var g = new Grammar(gb);

                    sre.LoadGrammar(g);

                    //イベントハンドラの追加
                    sre.SpeechRecognized += SreSpeechRecognized;
                    sre.SpeechHypothesized += SreSpeechHypothesized;
                    sre.SpeechRecognitionRejected += SreSpeechRecognitionRejected;

                    //認識の開始
                    using (Stream s = source.Start())
                    {
                        sre.SetInputToAudioStream(s,
                                                  new SpeechAudioFormatInfo(
                                                      EncodingFormat.Pcm, 16000, 16, 1,
                                                      32000, 2, null));

                        Console.WriteLine("認識開始:");

                        sre.RecognizeAsync(RecognizeMode.Multiple);

                        Console.ReadLine();

                    }
                }
            }
        }

        private  static RecognizerInfo GetKinectRecognizer()
        //認識エンジンを直に設定
        {
            return SpeechRecognitionEngine.InstalledRecognizers().Where(r=>r.Id=="SR_MS_en-US_Kinect_10.0").FirstOrDefault();
        }

        static void SreSpeechRecognitionRejected(object sender,SpeechRecognitionRejectedEventArgs e)
        {
            Console.WriteLine("\n認識できません。");
        }

        static void SreSpeechHypothesized(object sender,SpeechHypothesizedEventArgs  e)
        {
            Console.Write("\r入力音声: \t{0}",e.Result.Text);
        }

        static void SreSpeechRecognized(object sender,SpeechRecognizedEventArgs e)
        {
            Console.WriteLine("\n認識しました。: \t{0}", e.Result.Text);

            switch (e.Result.Text)
            {
                case "up":
                    CamUp();
                    break;
                case "down":
                    CamDown();
                    break;
                case "init":
                    CamInit();
                    break;
                case "suihei":
                    CamInit();
                    break;
            }

        }

        //カメラを上に
        static void CamUp()
        {
            var nowangle = cam.ElevationAngle + 5;

            if (nowangle > 25)
            {
                cam.ElevationAngle = 25;
            }
            else
            {
                cam.ElevationAngle = nowangle;
            }
        }
        //カメラを下に
        static void CamDown()
        {
            var nowangle = cam.ElevationAngle - 5;

            if (nowangle < -25)
            {
                cam.ElevationAngle = -25;
            }
            else
            {
                cam.ElevationAngle = nowangle;
            }
        }

        //カメラを水平に
        static void CamInit()
        {
            cam.ElevationAngle = 0;
        }

    }

}



--------------------------------------------------------------------------------

ソースコードを見ればわかると思いますが、「up」、[down」で上下にカメラが首を振ります。
「init」、「suihei」で初期位置(水平位置)に移動します。
KINECTの可動範囲は27°~-27°らしいですが壊れると困るので念のために25°~-25°までにしています。
ローマ字でも認識してくれます。すべてではないでしょうけどね。
初めは初期位置にするのに「zero」にしていたのですが「r」の発音が悪いらしくなかなか認識してくれないので変更しました^^;

次はこのソースを少し変更して日本語で認識できるようにします。

0 件のコメント:

コメントを投稿