F# + KINECT SDK Beta2で音声認識 #kinectsdk_ac
この記事はKINECT SDK Advent Calendar 2011 : ATNDの12月16日分です。
今回はKINECT SDKに同梱されているサンプルプログラム「Speech」と同等のものをF#で書いてみました。
このサンプルはred、blue、greenの3単語を判別するコードで、KINECT SDKでの音声認識プログラムとしては一番わかりやすいと思います。
環境
中身
今回はコンソールアプリケーションです。
open System open System.IO open System.Linq open Microsoft.Research.Kinect.Audio open Microsoft.Speech.AudioFormat open Microsoft.Speech.Recognition let getKinectRecognizer () = let matchingFunc (r:RecognizerInfo) = let mutable value = "" r.AdditionalInfo.TryGetValue("Kinect", &value) |> ignore "True".Equals(value, StringComparison.InvariantCultureIgnoreCase) && "en".Equals(r.Culture.Name, StringComparison.InvariantCultureIgnoreCase) SpeechRecognitionEngine.InstalledRecognizers().Where(matchingFunc).FirstOrDefault() let dumpRecordedAudio (audio:RecognizedAudio) = let rec findNextFileNumber num = let filename = "RetainedAudio_" + (string num) + ".wav" if filename |> (File.Exists >> not) then filename else findNextFileNumber (num+1) if audio = null then () let filename = findNextFileNumber 0 Console.WriteLine("\nWriting file: {0}", filename) use file = new FileStream(filename, System.IO.FileMode.CreateNew) audio.WriteToWaveStream(file) let sreSpeechRecognized (sre:SpeechRecognitionEngine) = sre.SpeechRecognized |> Observable.subscribe (fun e -> Console.WriteLine("\nSpeech Recognized: \t{0}", e.Result.Text) ) |> ignore let sreSpeechHypothesized (sre:SpeechRecognitionEngine) = sre.SpeechHypothesized |> Observable.subscribe (fun e -> Console.Write("\rSpeech Hypothesized: \t{0}", e.Result.Text) ) |> ignore let sreSpeechRecognitionRejected (sre:SpeechRecognitionEngine) = sre.SpeechRecognitionRejected |> Observable.subscribe begin fun e -> Console.WriteLine("\nSpeech Rejected") if e.Result <> null then dumpRecordedAudio(e.Result.Audio) end |> ignore let main () = use source = new KinectAudioSource() source.FeatureMode <- true source.AutomaticGainControl <- false source.SystemMode <- SystemMode.OptibeamArrayOnly let ri = getKinectRecognizer() if ri = null then Console.WriteLine("Could not find Kinect speech recognizer. Please refer to the sample requirements.") else Console.WriteLine("Using: {0}", ri.Name) use sre = new SpeechRecognitionEngine(ri.Id) let colors = new Choices() [| "red";"green"; "blue" |] |> colors.Add let gb = new GrammarBuilder() gb.Culture <- ri.Culture colors |> gb.Append let g = new Grammar(gb) sre.LoadGrammar(g) sre |> sreSpeechRecognized sre |> sreSpeechHypothesized sre |> sreSpeechRecognitionRejected use s = source.Start() sre.SetInputToAudioStream(s, new SpeechAudioFormatInfo( EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null)) Console.WriteLine("Recognizing. Say: 'red', 'green' or 'blue'. Press ENTER to stop") sre.RecognizeAsync(RecognizeMode.Multiple) Console.ReadLine() |> ignore Console.WriteLine("Stopping recognizer ...") sre.RecognizeAsyncStop() [<EntryPoint>] main ()
Kinectのオーディオ・ソースを利用
Kinectのオーディオ・ソースの準備とKinectAudioSource.SystemModeプロパティの設定、オートマティック・ゲイン・コントロールの無効化設定を行っています。
use source = new KinectAudioSource() source.FeatureMode <- true source.AutomaticGainControl <- false source.SystemMode <- SystemMode.OptibeamArrayOnly
F#ではuseキーワードを使うことで、含まれているコードブロックの最後でリソースを自動開放してくれます。
認識エンジンの準備
まず、SpeechRecognitionEngineオブジェクトを生成します。
let ri = getKinectRecognizer() if ri = null then Console.WriteLine("Could not find Kinect speech recognizer. Please refer to the sample requirements.") Console.WriteLine("Using: {0}", ri.Name) use sre = new SpeechRecognitionEngine(ri.Id)
次に、構文を構築しSpeechRecognitionEngineオブジェクトに読み込ませる作業です。
use sre = new SpeechRecognitionEngine(ri.Id) let colors = new Choices() [| "red";"green"; "blue" |] |> colors.Add let gb = new GrammarBuilder() gb.Culture <- ri.Culture colors |> gb.Append let g = new Grammar(gb) sre.LoadGrammar(g)
音声認識機能の開始、停止
ストリームを開き、認識エンジンに渡してから認識機能を開始させます。
use s = source.Start() sre.SetInputToAudioStream(s, new SpeechAudioFormatInfo( EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null)) Console.WriteLine("Recognizing. Say: 'red', 'green' or 'blue'. Press ENTER to stop") sre.RecognizeAsync(RecognizeMode.Multiple) Console.ReadLine() |> ignore Console.WriteLine("Stopping recognizer ...") sre.RecognizeAsyncStop()
コンソールから一行入力が行われたら認識機能を停止させます。
音声認識通知
信頼性の高い 1 つ以上の句を検索したときはSpeechRecognized、音声の一部が一時的に認識されたときはSpeechHypothesized、信頼性の低い候補句しか返せなかったときはSpeechRecognitionRejected経由で通知が行われるようです。
今回はSpeechRecognitionRejectedのときにdumpRecordedAudioを呼び出して音声を記録するようにしています。
let dumpRecordedAudio (audio:RecognizedAudio) = let rec findNextFileNumber num = let filename = "RetainedAudio_" + (string num) + ".wav" if filename |> (File.Exists >> not) then filename else findNextFileNumber (num+1) if audio = null then () let filename = findNextFileNumber 0 Console.WriteLine("\nWriting file: {0}", filename) use file = new FileStream(filename, System.IO.FileMode.CreateNew) audio.WriteToWaveStream(file)
実行結果はSpeechサンプルプログラムと同じになります。
音声の認識も簡単に行えるのはすばらしいですね。