【问题标题】:Issue distinguishing commands from normal speech with SAPI使用 SAPI 将命令与正常语音区分开来
【发布时间】:2011-12-18 19:54:55
【问题描述】:

我正在做一个个人项目,涉及我公寓里的麦克风,我可以向它发出口头命令。为此,我一直在使用 Microsoft Speech API,特别是 C# 中 System.Speech.Recognition 中的 RecognitionEngine。我构造一个语法如下:

// validCommands is a Choices object containing all valid command strings
// recognizer is a RecognitionEngine
GrammarBuilder builder = new GrammarBuilder(recognitionSystemName);
builder.Append(validCommands);
recognizer.SetInputToDefaultAudioDevice();
recognizer.LoadGrammar(new Grammar(builder));
recognizer.RecognizeAsync(RecognizeMode.Multiple);

// etc ...

当我实际给它一个命令时,这似乎工作得很好。它还没有误认我的命令之一。不幸的是,它也倾向于将随机谈话作为命令!我试图通过在命令 Choices 对象前加上一个“名称”(recognitionSystemName)来改善这一点,我将系统称为。奇怪的是,这似乎没有帮助。我将它限制为一组预定的命令短语,所以我认为它能够检测到语音是否不是任何字符串。我最好的猜测是它假设所有声音都是命令并从命令集中选择最佳匹配。任何有关改进此系统使其不再触发非针对它的对话的建议都会非常有帮助。

编辑:我已将名称识别器移至单独的 SpeechRecognitionEngine,但准确性很差。这是我写的一些测试代码来检查准确性:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Speech.Recognition;

namespace RecognitionAccuracyTest
{
    class RecognitionAccuracyTest
    {
        static int recogcount;
        [STAThread]
        static void Main()
        {
            recogcount = 0;
            System.Console.WriteLine("Beginning speech recognition accuracy test.");

            SpeechRecognitionEngine recognizer;
            recognizer = new SpeechRecognitionEngine(new System.Globalization.CultureInfo("en-US"));
            recognizer.SetInputToDefaultAudioDevice();
            recognizer.LoadGrammar(new Grammar(new GrammarBuilder("Octavian")));
            recognizer.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(recognizer_SpeechHypothesized);
            recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(recognizer_SpeechRecognized);
            recognizer.RecognizeAsync(RecognizeMode.Multiple);

            while (true) ;
        }

        static void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            System.Console.WriteLine("Recognized @ " + e.Result.Confidence);
            try
            {
                if (e.Result.Audio != null)
                {
                    System.IO.FileStream stream = new System.IO.FileStream("audio" + ++recogcount + ".wav", System.IO.FileMode.Create);
                    e.Result.Audio.WriteToWaveStream(stream);
                    stream.Close();
                }
            }
            catch (Exception) { }
        }

        static void recognizer_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        {
            System.Console.WriteLine("Hypothesized @ " + e.Result.Confidence);
        }
    }
}

如果名称是“Octavian”,它会识别“Octopus”、“Octagon”、“Volkswagen”和“哇,真的吗?”等内容。我可以清楚地听到相关音频剪辑的差异。任何关于让它不那么糟糕的想法都会很棒。

【问题讨论】:

  • 那么你最终是如何解决你的问题的。我不确定标记的答案是否真的解决了它。你能分享什么让它变得更好。我似乎处于类似的情况,识别器只是识别很多并且具有很高的置信率。
  • 标记的答案是边际改进。为了让它变得更好,我所做的是切换到 SRGS 语法,并将 元素作为第一项。然后,当我得到结果时,我将第一个单词与我的系统名称进行比较。如果不匹配,我会丢弃结果。有时我必须重复自己,但这样做实际上消除了误报。
  • 感谢您抽出宝贵时间。 你的意思是像这里的 MS 例子吗? msdn.microsoft.com/en-us/library/ms723634%28v=vs.85%29.aspx
  • 我很确定我在这里的问题也是解决此问题的另一种方法。 stackoverflow.com/questions/18821566/…
  • 我使用了 SrgsRuleRef 类和 SrgsDocument 对象来生成我的语法。 SrgsRuleRef.Dictation 代表听写元素 - 不幸的是,这方面的文档不存在,所以我还没有想出如何将它限制为一个听写单词,但无论如何它似乎工作得很好。

标签: c# speech-recognition sapi speech-to-text noise


【解决方案1】:

请确保我理解,您需要一个短语来区分系统的命令,例如“butler”或“Siri”。所以,你会说“巴特勒,打开电视”。您可以将其构建到您的语法中。

这是一个简单语法示例,它需要一个开头短语才能识别命令。它使用语义结果来帮助您理解所说的内容。在这种情况下,用户必须说“打开”或“请打开”或“你能打开吗”

    private Grammar CreateTestGrammar()
    {
        // item
        Choices item = new Choices();
        SemanticResultValue itemSRV;
        itemSRV = new SemanticResultValue("I E", "explorer");
        item.Add(itemSRV);
        itemSRV = new SemanticResultValue("explorer", "explorer");
        item.Add(itemSRV);
        itemSRV = new SemanticResultValue("firefox", "firefox");
        item.Add(itemSRV);
        itemSRV = new SemanticResultValue("mozilla", "firefox");
        item.Add(itemSRV);
        itemSRV = new SemanticResultValue("chrome", "chrome");
        item.Add(itemSRV);
        itemSRV = new SemanticResultValue("google chrome", "chrome");
        item.Add(itemSRV);
        SemanticResultKey itemSemKey = new SemanticResultKey("item", item);

        //build the permutations of choices...
        GrammarBuilder gb = new GrammarBuilder();
        gb.Append(itemSemKey);


        //now build the complete pattern...
        GrammarBuilder itemRequest = new GrammarBuilder();
        //pre-amble "[I'd like] a"
        itemRequest.Append(new Choices("Can you open", "Open", "Please open"));

        itemRequest.Append(gb);

        Grammar TestGrammar = new Grammar(itemRequest);
        return TestGrammar;
    }

然后您可以使用以下内容处理语音:

RecognitionResult result = myRecognizer.Recognize();

并检查语义结果,例如:

if(result.Semantics.ContainsKey("item"))
{
   string s = (string)result.Semantics["item"].Value;
}

【讨论】:

  • 这或多或少是我目前拥有的,除了我刚刚使用哈希表而不是语义结果键值对。因此,如果我正确阅读了您的答案,那么我所犯的主要错误就是在与我的命令选择相同的 GrammarBuilder 中构建我的短语。这是正确的吗?
  • 您不必使用 SemanticResultValue。我刚刚有可用于复制粘贴的代码示例。但是,我认为答案是您想在语法中添加两件事:“唤醒”表达式,然后为可用命令添加选项列表。否则,你的字典里有什么?如果唤醒表达式只是你字典中的一个孩子,我认为你不会得到你想要的结果。
  • msdn.microsoft.com/en-us/library/hh361662.aspx 有一个很好的例子。语法要求短语“我想飞出”。然后在所需短语之后添加一个有效选项列表。
  • 从我发布的代码来看,我的语法是由一个 GrammarBuilder 构建的。该 GrammarBuilder 使用系统名称(例如“Butler”)进行初始化,然后附加一个带有有效命令的 Choices 对象。我认为这与您在第一条评论中所说的关于我的语法中的内容相对应。我本来打算这样做的:msdn.microsoft.com/en-us/library/ms554229.aspx 或多或少有我正在做的事情,但问题是它仍然会收集很多不是针对它作为命令的正常对话。
  • 好的,我现在更清楚地看到了您的示例。我误解了识别系统名称是什么。所以,是的,看来你正在按照我的建议做。
【解决方案2】:

我也有同样的问题。 我使用的是 Microsoft Speech Platform,因此在准确性等方面可能会有所不同。

我使用 Claire 作为唤醒命令,但它确实也可以将不同的单词识别为 Claire。问题是引擎会听到您说话并搜索最接近的匹配项。

我没有找到一个很好的解决方案。 您可以尝试使用 Confidence 字段过滤已识别的语音。但是我选择的识别器引擎不是很可靠。 我只是将我想识别的每个单词都放在一个大的 SRGS.xml 中,并将重复值设置为 0-。我只接受公认的句子,因为 Claire 是第一个词。 但是这个解决方案不是我想要的,因为它没有我希望的那么好,但它仍然有一点改进。

我目前很忙,我会随着进度发布更多信息。

编辑 1: 作为对 Dims 所说的评论: 可以在 SRGS 语法中添加“垃圾”规则。你可能想调查一下。 http://www.w3.org/TR/speech-grammar/

【讨论】:

  • 我热切期待听到您的进步,但垃圾似乎旨在防止句子中间出现单个单词或短语。来自规范:Defines a rule that may match any speech up until the next rule match, the next token or until the end of spoken input. A grammar processor must accept grammars that contain special references to GARBAGE. The behavior GARBAGE rule is implementation-specific. A user agent should be capable of matching arbitrary spoken input up to the next token but may treat GARBAGE as equivalent to NULL (match no spoken input).
【解决方案3】:

原则上,您需要更新语法或字典以在其中包含“空”或“任何”条目。

【讨论】:

  • 好吧,这听起来很合理。我该怎么做呢?
  • 抱歉不熟悉这个特定的API。
【解决方案4】:

是否可能只需要在创建/加载要使用的语法之前运行 UnloadAllGrammars()?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-11
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    相关资源
    最近更新 更多