Teil 3: Verarbeitung von Audiodaten mit Kinect

Kinect hat Ohren (Teil 2)
Kommentare

Windows Developer

Der Artikel „Kinect hat Ohren“ von Tam Hanna ist erstmalig erschienen im Windows Developer 6.2012
Audiodaten speichern
Das vorherige Beispiel zeigt zwar schön aussehende Koordinaten,

Windows Developer

Der Artikel „Kinect hat Ohren“ von Tam Hanna ist erstmalig erschienen im Windows Developer 6.2012

Audiodaten speichern

Das vorherige Beispiel zeigt zwar schön aussehende Koordinaten, hat ansonsten aber wenig Nutzwert. Allerdings spricht nichts dagegen, die vom Sensor angelieferten Samples abzuspeichern und später wieder abzuspielen. Microsoft bietet auf Channel9 ein AudioRecorder genanntes Beispiel an, das diesen Prozess sehr schön vorzeigt [1]. Als Speicherformat verwendet es Wave-Dateien. Diese Dateien – in der Regel haben sie die Dateiendung .wav – sind das primitivste Audioformat. Nach einem das Format der folgenden Daten festlegenden Header folgen nacheinander die vom A/D-Konverter gelieferten Samples. Will man eine .wav-Datei abspielen, informiert man sich über das Format und schreibt die Datenwörter direkt in die Ausgabe. Das Abspielen der gespeicherten .wav-Dateien wird im Beispiel über ein MediaElement-Objekt realisiert. Auch hier findet sich keine Raketenphysik.

Spracherkennung

Wesentlich interessanter ist da schon die Vorgehensweise zur Spracherkennung. Kinect arbeitet nämlich anders als klassische Diktatprogramme mit einer Grammatik. Das dahinter stehende Konzept beruht auf der Überlegung, dass Benutzer rational handeln. Ruft man beispielsweise bei einer Privatbank an, ordert ein rational handelnder Kunde nur höchst selten Kuchen – die Anfrage nach „Konten“ klingt hingegen höchst vernünftig. Diese Informationen erlauben eine signifikante Reduktion der „Problemdomäne“. Anstatt der gesamten englischen Sprache muss der Rechner fortan nur mehr auf einige bestimmte „Terms“ lauschen. Das erleichtert die Spracherkennung wesentlich, da es nun weniger zu berücksichtigende Möglichkeiten gibt.

Übrigens soll laut Analysen in Blogs und Foren auch die derzeit sehr populäre Siri-Engine mit einer Grammatik arbeiten. Allerdings ist die Grammatik so komplex, dass bei kurzen Tests der Eindruck einer „realen Person“ entsteht. Diese Technik wollen wir uns im Beispiel SusKinect7 näher ansehen – auch eine WPF-Applikation. Wie immer benötigen wir neben der mittlerweile standardisierten Inkludierung des Kinect-API zusätzlich eine Referenz auf den Namespace Microsoft.Speech, der auf der Maschine des Autors im Verzeichnis C:Program FilesMicrosoft Speech Platform SDKAssemblyMicrosoft.Speech.dll residiert und mittels Browser lokalisiert werden muss.

Die Speech Recognition Engine von Kinect integriert sich nahtlos in das allgemeine Speech-Recognition-Framework des Betriebssystems. Daher muss man sie vor der Verwendung erst aus der Auswahl an Engines herauspulen. Microsoft empfiehlt dazu folgendes Codestück in Listing 3.

Listing 3

private static RecognizerInfo GetKinectRecognizer()
{
  Func matchingFunc = r =>
  {
    string value;
    r.AdditionalInfo.TryGetValue("Kinect", out value);
    return "True".Equals(value, StringComparison.InvariantCultureIgnoreCase) && "en-US".Equals(r.Culture.Name, StringComparison.InvariantCultureIgnoreCase);
  };
  return SpeechRecognitionEngine.InstalledRecognizers().Where(matchingFunc).FirstOrDefault();
}  

An sich gibt es hier nicht allzu viel zu sehen: Wir fragen ab, ob einer der Recognizer einen auf Kinect* matchenden Namen hat. Wenn ja, liefern wir ihn als Rückgabewert an die aufrufende Methode zurück.

Die Initialisierung der mittels GetKinectRecognizer gefundenen Spracherkennungs-Engine erfolgt primär in der Methode SetupSRE, deren Methodenrumpf aussieht wie in Listing 4.

Listing 4

void setupSRE()
{
  RecognizerInfo ri = GetKinectRecognizer();
  if (ri == null)
  {
    MessageBox.Show("Speech SDK fehlt - siehe Artikel 1");
    this.Close();
  }
  try
  {
    mySRE = new SpeechRecognitionEngine(ri.Id);
  }
  catch
  {
    this.Close();
  }

  var numbers = new Choices();
  numbers.Add("one");
  numbers.Add("two");
  numbers.Add("three");
  numbers.Add("four");
  numbers.Add("five");
  numbers.Add("six");
  numbers.Add("seven");
  numbers.Add("eight");
  numbers.Add("nine");
  numbers.Add("zero");

  var gb = new GrammarBuilder();
  gb.Culture = ri.Culture;
  gb.Append(numbers);

  // Create the actual Grammar instance, and then load it into the speech recognizer. 
  var g = new Grammar(gb);


  mySRE.LoadGrammar(g);
  mySRE.SpeechRecognized += sre_SpeechRecognized;
  mySRE.SpeechHypothesized += sre_SpeechHypothesized;
  mySRE.SpeechRecognitionRejected += new EventHandler(sre_SpeechRecognitionRejected);
}  

Als Erstes beschaffen wir uns in dieser Routine mit der vorher besprochenen Funktion die ID der zu verwendenden Sprachsynthese-Engine. Danach erstellen wir eine neue Instanz der Klasse SpeechRecognitionEngine, die zur Kommunikation zwischen der Engine und der Applikation dient.

Im nächsten Schritt bauen wir eine Instanz des Choices-Objekts zusammen. Choices-Objekte sind die elementarsten Teile von Grammatiken. Sie bilden die möglichen Eingaben des Benutzers (in unserem Fall die zehn möglichen Ziffern einer Telefonnummer) ab. Ist das Choices-Objekt komplett, erstellen wir mit GrammarBuilder daraus Grammatikparameter. Aus diesen erstellen wir dann ein Grammatikobjekt, das wir an die Speech Recognition Engine übergeben. Zu guter Letzt weisen wir den drei Events Handler zu, sodass die SRE mit unserer Applikation kommunizieren kann. Im Konstruktor rufen wir die Methode nach dem Erstellen des Streams auf:

myAudioSource.MicArrayMode = MicArrayMode.MicArrayAdaptiveBeam;
myStream = myAudioSource.Start();
setupSRE();
mySRE.SetInputToAudioStream(myStream, new SpeechAudioFormatInfo(
             EncodingFormat.Pcm, 16000, 16, 1,
             32000, 2, null));
mySRE.RecognizeAsync(RecognizeMode.Multiple);  
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -