Sphinx应用程序编写

2016/06/30 15:21
阅读数 256

Pocketsphinx API 核心理念

     Pocketsphinx API 被设计是为了减轻编写语音识别功能应用程序。

  1. 由于使用抽象类,所以在源代码和二进制文件兼容方面,更能保持稳定。
  2. 因为它完全可重入,所以在同一进程中拥有多个编码器也不会出现问题。
  3. 在运行时,新的语言模型的接口(在sphinxbase)支持线性多模型插值。
  4. 它能大幅度减少代码量而且能明显减少内存消耗。

相关文档见:http://cmusphinx.sourceforge.net/api/pocketsphinx/

基本用法(hello world

你需要知道几个关键的点如何使用应用程序接口(API):

  1. 命令行通过外部<cmd_ln.h>来解析;
  2. 一切都需要一个ps_decoder_t*作为第一个参数。

为了说明新的接口,我们将通过一个简单的“hello world”的例子。这个例子为unix源文件和汇编程序。我们将创建一个叫hello_ps.c的C源文件。我们使用如下命令来编译:

    gcc -o hello_ps hello_ps.c \

    -DMODELDIR=\"`pkg-config --variable=modeldir pocketsphinx`\"

`pkg-config --cflags --libs pocketsphinx sphinxbase`

请注意,编译错误在这里意味着你没有仔细阅读教程和不遵循上述安装指南。例如pocketsphinx需要通过pkg-config系统来正确安装。为了检查pocketsphinx正确安装与否,只要在命令行运行 pkg-config --cflags --libs pocketsphinx sphinxbase 就可以从输出结果看出。

-I/usr/local/include/sphinxbase  -I/usr/local/include/pocketsphinx 

-L/usr/local/lib -lpocketsphinx -lsphinxbase –lsphinxad

 

pkg-config --variable=modeldir pocketsphinx

显示结果输出:/usr/local/share/pocketsphinx/model

 

补充:gcc -o recog recog.c \-DMODELDIR=\"/usr/local/share/pocketsphinx/model\"  -I/usr/local/include/sphinxbase  -I/usr/local/include/pocketsphinx  -L/usr/local/lib -lpocketsphinx -lsphinxbase -lsphinxad

初始化

首先我们需要做的是创建一个配置对象,由于某种原因叫作cmd_ln_t。我们将按如下程序这样做:

#include <pocketsphinx.h>

 

int main(int argc, char *argv[])

{

        ps_decoder_t *ps;

        cmd_ln_t *config;

 

        config = cmd_ln_init(NULL, ps_args(), TRUE,

                          "-hmm",MODELDIR "/hmm/en_US/ hub4wsj_sc_8k",

                          "-lm", MODELDIR "/lm/en/turtle.DMP",

                          "-dict", MODELDIR "/lm/en/turtle.dic",

                             NULL);

        if (config == NULL)

                return 1;

 

        return 0;

}

 

该cmd_ln_init()功能采用可变数目的空结束NULL的字符串参数。第一个参数是之前要更新的cmd_ln_t *。第二参数是一个数组参数定义—通过调用ps_args()来进行设置。第三个参数是一个标志,告诉参数解析器将是“严格”的—如果这是真的,然后重复的参数或未知参数会导致解析失败。

该MODELDIR宏定义是在GCC命令行中使用pkg-config从PocketSphinx配置中获得modeldir变量。在windows系统中,你可以简单的增加一个预处理宏定义到代码中,像这样:

          #define MODELDIR "c:/sphinx/model"

(无论你的模型安装在哪个目录下),现在,为了初始化解码器,使用ps_init如下:

ps = ps_init(config);

        if (ps == NULL)

                return 1;

 

解码文件流

现在现场音频输入受到一些特定平台的影响,这将限制我们自已去解码音频文件。“turtle”语言模式识别的一个非常简单的“robot control”语言,其中包括一些诸如“go forward ten meters”的短语。事实上,一个音频文件包含在PocketSphinx源代码的句子中。你可以在test/data/goforward.raw中找到。把它复制到当前目录。如果你想创建自己的版本,需要一个单声道,小端,无头16-bit PCM有符号,采样率为16KHZ的音频文件。

 

为了这样做,首先我们打开文件:

        FILE *fh;

 

        fh = fopen("goforward.raw", "rb");

        if (fh == NULL) {

                perror("Failed to open goforward.raw");

                return 1;

        }

然后使用ps_decode_raw()进行解码:

        rv = ps_decode_raw(ps, fh, "goforward", -1);

        if (rv < 0)

                return 1;

现在,为了假设,我们可以使用ps_get_hyp():

        char const *hyp, *uttid;

        int rv;

        int32 score;

        hyp = ps_get_hyp(ps, &score, &uttid);

        if (hyp == NULL)

                return 1;

        printf("Recognized: %s\n", hyp);

从内存中解码音频数据

现在我们将再次解码相同的文件,但是使用API从内存块中解码音频数据。在这种情况下,首先我们需要使用ps_start_utt()开始说话:

        fseek(fh, 0, SEEK_SET);

        rv = ps_start_utt(ps, "goforward");

        if (rv < 0)

                return 1;

我们将每次从文件中读取512大小的样本,使用ps_process_raw()把它们放到解码器中:

        int16 buf[512];

        while (!feof(fh)) {

            size_t nsamp;

            nsamp = fread(buf, 2, 512, fh);

            rv = ps_process_raw(ps, buf, nsamp, FALSE, FALSE);

        }

然后我们需要使用ps_end_utt()去标记说话的结尾处:

        rv = ps_end_utt(ps);

        if (rv < 0)

                return 1;

以相同精确的方式运行来检索假设的字符串:

        hyp = ps_get_hyp(ps, &score, &uttid);

        if (hyp == NULL)

                return 1;

        printf("Recognized: %s\n", hyp);

清理

使用ps_free()对对象进行清理,返回使用ps_init()。你不应该释放配置对象。

代码清单

 1 #include <pocketsphinx.h>
 2 
 3 int main(int argc, char *argv[])  4 {  5     ps_decoder_t *ps;  6     cmd_ln_t *config;  7     FILE *fh;  8     char const *hyp, *uttid;  9         int16 buf[512]; 10     int rv; 11  int32 score; 12 
13     config = cmd_ln_init(NULL, ps_args(), TRUE, 14                  "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k", 15                  "-lm", MODELDIR "/lm/en/turtle.DMP", 16                  "-dict", MODELDIR "/lm/en/turtle.dic", 17  NULL); 18     if (config == NULL) 19         return 1; 20     ps = ps_init(config); 21     if (ps == NULL) 22         return 1; 23 
24     fh = fopen("goforward.raw", "rb"); 25     if (fh == NULL) { 26         perror("Failed to open goforward.raw"); 27         return 1; 28  } 29 
30     rv = ps_decode_raw(ps, fh, "goforward", -1); 31     if (rv < 0) 32         return 1; 33     hyp = ps_get_hyp(ps, &score, &uttid); 34     if (hyp == NULL) 35         return 1; 36     printf("Recognized: %s\n", hyp); 37 
38         fseek(fh, 0, SEEK_SET); 39         rv = ps_start_utt(ps, "goforward"); 40     if (rv < 0) 41         return 1; 42         while (!feof(fh)) { 43  size_t nsamp; 44             nsamp = fread(buf, 2, 512, fh); 45             rv = ps_process_raw(ps, buf, nsamp, FALSE, FALSE); 46  } 47         rv = ps_end_utt(ps); 48     if (rv < 0) 49         return 1; 50     hyp = ps_get_hyp(ps, &score, &uttid); 51     if (hyp == NULL) 52         return 1; 53     printf("Recognized: %s\n", hyp); 54 
55  fclose(fh); 56  ps_free(ps); 57     return 0; 58 }

高级用法

对于使用更复杂的老API,有一些明显的不同地点:

  1. 得到部分和全部假设不再有单独的功能;
  2. 词语切分是通过访问迭代器而不是返回的数组或列表;
  3. 语言模型的转换是通过外部(<ngram_model.h>)。

首先这些都是简单的。在这之前,你必须使用uttproc_partial_result()得到部分结果(例如在uttproc_end_utt()前),使用uttproc_result()得到全部结果。现在,ps_get_hyp()能工作在两种方式下。

对于字的分割,API提供了一个遍历所有字序列的迭代器对象。这个迭代器对象是一个抽象类,这个抽象类为一些访问器提供获取每个字的时间点,分数和(最有趣的)后验概率。

最后,语言模型切换是完全不同的。解码器总是与一个语言模型集对象联系在一起。切换语言模型是通过以下:

  1. 得到一个句柄然后给语言模型集对象:ps_get_lmset()
  2. 选择一个新的语言模型:ngram_model_set_select()
  3. 告诉解码器语言模型集已更新:ps_update_lmset()

                                                                                                                                           翻译于2011年9月21日

参考官网:http://cmusphinx.sourceforge.net/wiki/tuturialpocketsphinx

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部