四、pocketsphinx应用编程

pocketsphinx应用编程
Jiangdg_VIP
http://blog.csdn.net/u012637501
译自:http://cmusphinx.sourceforge.net/wiki/tutorialpocketsphinx
    Pocketsphinx是一个库,它依赖于另一个库-SphinxBase。在整个CMUSphinx工程项中,SphinxBase库为项目提供所需的常用功能。在正常使用PocketSphinx,需要同时安装Pocketsphinx和Sphinxbase库,通过安装这两个库我们可以实现在linux系统或windows系统中使用Pocketsphinx进行语音开发
    首先,我们需要将这两个库同时解压到同一目录下,如果是在windows中,还需要将'sphinxbase-X.Y"或者"pocketsphinx-X.Y"(其中X.Y为sphinxbase的版本号)改名为"sphinxbase"或"pocketsphinx"。
一.linux下环境搭建
    即为Linux, Solaris, FreeBSD等系统安装 Pocketsphinx库、sphinxbase库。
1.安装sphinxbase库
(1)./autogen.sh:生成configure文件
(2)./configure
(3)make
(4)make install
    通过上面4步, sphinxbase库会被安装到/usr/local目录。这里需要注意的是,并不是每个系统都是自动从这个目录加载库。为了能够正确加载 这些库,我们可能需要配置路径去寻找共享库。这里提供两种方法:
 a.修改/etc/ld.so.conf文件(永久有效)
    $vim  /etc/ld.so.conf
  添加:/usr/local/lib
             /usr/local/lib/pkconfig
    $ldconfig :使其生效。ldconfig将 /etc/ld.so.conf 列出的路径下的库文件缓存到 /etc/ld.so.cache以供使用系统是通过读取这个库列表文件来加快搜索 链接路径的速度的
b.修改环境变量(环境变量只对当前终端有效)
  export LD_LIBRARY_PATH=/usr/local/lib
  export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig  
2.安装pocketsphinx库
(1)$./configure
(2)$make
(3)$make install
3.测试安装结果
    为了测试是否安装成功,我们可以运行pocketsphinx_continuous,然后观察其是否能识别从麦克风输入的语音。
    $ pocketsphinx_continuous
二、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 "例子来说明新的API接口,这个例子为unix源文件和汇编程序。
1.建立一个C源文件hello_ps.c,下面是它的编译命令.
$gcc -o  hello_ps  hello_ps.c  -DMODELDIR=\"`pkg-config --variable=modeldir pocketsphinx`\" `pkg-config --cflags --libs pocketsphinx sphinxbase`(编译源码,gcc的-D选项,指定宏定义)
    使用上述命令对该C文件在Linxu平台上进行编译。如果编译出错,则说明你没有仔细阅读本教程或者没有正确安装pocketsphinx。比如说,pocketsphinx需要通过pkg-config系统来正确安装。为了检查pocketsphinx正确安装与否,只要在命令行运行 pkg-config --cflags --libs pocketsphinx sphinxbase 就可以从输出结果看出。即,运行命令:
$ pkg-config --cflags --libs pocketsphinx sphinxbase
pkg-config工具可以获得一个库的编译和连接等信息,如果输出:
    -I  /usr/local/include  -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
2.初始化-创建配置对象cmd_ln_t
    首先我们需要建立一个配置对象cmd_ln_t,可以通过一个标准模版(方法)来创建该配置对象,代码如下:
#include <pocketsphinx.h>
int   main(int argc, char *argv[]) 
{
        ps_decoder_t *ps;
        cmd_ln_t *config;                                                    //建立配置对象 cmd_ln_t
        config = cmd_ln_init(NULL, ps_args(), TRUE,        //cmd_ln_init() 函数
                             "-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;
}
源代码解析:
(1)cmd_ln_init() 函数接受字符串类型的参数,且参数的个数是可变,其作用是返回一个配置对象类型指针。第一个参数是之前要更新的cmd_ln_t *;第二个参数是 一个 参数定义的 数组—通过调用ps_args()来进行设置;第三个参数是一个标识,用来告诉参数解析器将是“严格”的。当参数设置为"TRUE"时,重复的参数或未知参数会导致解析失败。
(2) MODELDIR宏被定义在GCC命令行中,主要是通过使用pkg-config 从PocketSphinx配置中获取modeldir变量来实现。
    在Windows中,我们可以通过在源代码中添加一个预定义,
    如:#define MODELDIR "c:/sphinx/model",(注意: c:/sphinx/model为你安装models位置路径 )
3.初始化解码器
 ps = ps_init(config);
        if (ps == NULL)
                return 1;
    即使用ps_init(config)函数,将配置对象指针变量为传入参数来初始化解码器。
4.解码一个音频文件
     解码的作用就是将音频文件转换为字符串 因为现场音频输入或多或少会与平台有关,所以我们在这里我们只解码已经录制好的音频文件。现有的"turtle"语言模型只能识别非常简单的"机器人控制"指令,比如识别"go forward ten meters"短语。实际上,在PocketSphinx源码中已经包含了一个非常有用的音频文件,其包含已经包含了这个句 子。这个文件在 test/data/goforward.raw,我们可以将它拷贝到当下(项目)目录下。
    当然,如果你想创建自己的版本,在录制音频文件的时候需要设置文件属性为:单声道、小端、16位PCM格式音频文件、频率16000HZ。音频文件录制(goforward.raw)好后, 为了正确使用它,需要做以下几步:
(1)打开文件,代码实现如下:
         FILE *fh;
        fh = fopen("goforward.raw", "rb");
        if (fh == NULL) {
                perror("Failed to open goforward.raw");
                return 1;
        }
(2)解码音频文件,调用ps_decode_raw()函数。
         rv = ps_decode_raw(ps, fh, "goforward", -1);
        if (rv < 0)
                return 1;
(3)得到解码的结果(概率最大的字串),调用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);
5.解码内存中的音频数据
    现在我们将再次解码相同的 test/data/goforward.raw音频文件, 这步同第四步作用一样,目的是解码音频文件。但是, 解码内存中的音频数据使用的是PocketSphinx  API接口,为此,我们使用ps_start_utt()函数开始说话。
(1)调用 ps_start_utt()函数开始说话
       fseek(fh, 0, SEEK_SET);
        rv = ps_start_utt(ps, "goforward");
        if (rv < 0)
                return 1;
(2)我们将每次从文件中读取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);
        }      
(3)使用ps_end_utt()方法标识说话结束
 rv = ps_end_utt(ps);
        if (rv < 0)
                return 1;
(4)以相同精确的方式运行来检索假设的字符串
   hyp = ps_get_hyp(ps, &score, &uttid);
        if (hyp == NULL)
                return 1;
        printf("Recognized: %s\n", hyp);
6.清理工作
    使用ps_free()释放使用ps_init()返回的对象,不用释放配置对象。

四、源代码(hello_ps.c)
#include <pocketsphinx.h>
int main(int argc, char *argv[])
{
 ps_decoder_t *ps;
 cmd_ln_t *config;
 FILE *fh;
 char const *hyp, *uttid;
        int16 buf[512];
 int rv;
 int32 score;

 //1、初始化:创建一个配置对象 cmd_ln_t *
 //cmd_ln_init函数第一个参数是我们需要更新的上一个配置,因为这里是初次创建,所以传入NULL;
 //第二个参数是一个定义参数的数组,如果使用的是标准配置的参数集的话可以通过调用ps_args()去获得。
 //第三个参数是是一个标志,它决定了参数的解释是否严格,如果为TRUE,那么遇到重复的或者未知的参
 //数,将会导致解释失败;
 //MODELDIR这个宏,指定了模型的路径,包括声学模型,语言模型和字典三个文件,是由gcc命令行传入,
 //我们通过pkg-config工具从PocketSphinx的配置中去获得这个modeldir变量
 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;
 //2、初始化解码器(语言识别就是一个解码过程,通俗的将就是将你说的话解码成对应的文字串)
 ps = ps_init(config);
 if (ps == NULL)
  return 1;

 //3、解码文件流
 //因为音频输入接口(麦克风)受到一些特定平台的影响,不利用我们演示,所以我们通过解码音频文件流
 //来演示PocketSphinx API的用法,goforward.raw是一个包含了一些诸如“go forward ten meters”等用来
 //控制机器人的短语(指令)的音频文件,其在test/data/goforward.raw。把它复制到当前目录
 fh = fopen("/dev/input/event14", "rb");
 if (fh == NULL) {
  perror("Failed to open goforward.raw");
  return 1;
 }
 //4、使用ps_decode_raw()进行解码
 rv = ps_decode_raw(ps, fh, NULL, -1);
 if (rv < 0)
  return 1;
 //5、得到解码的结果(概率最大的字串) hypothesis
 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, NULL);
 if (rv < 0)
  return 1;
        while (!feof(fh)) {
    rv = ps_start_utt(ps, NULL);
        if (rv < 0)
                return 1;

  printf("ready:\n");
            size_t nsamp;
            nsamp = fread(buf, 2, 512, fh);
  printf("read:\n");
   //我们将每次从文件中读取512大小的样本,使用ps_process_raw()把它们放到解码器中:
            rv = ps_process_raw(ps, buf, nsamp, FALSE, FALSE);
  printf("process:\n");
        }
  //我们需要使用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);
 }
 //6、清理工作:使用ps_free()释放使用ps_init()返回的对象,不用释放配置对象。
 fclose(fh);
        ps_free(ps);
 return 0;
}











    

你可能感兴趣的:(sphinx,应用程序,语音识别)