PocketSphinx语音识别系统的编程


分类: 语音识别与TTS Linux 嵌入式   6997人阅读  评论(10)  收藏  举报

PocketSphinx语音识别系统的编程

zouxy09@qq.com

http://blog.csdn.net/zouxy09

 

      关于语音识别的基础知识和sphinx的知识,具体可以参考我的另外的博文:

语音识别的基础知识与CMUsphinx介绍:

http://blog.csdn.net/zouxy09/article/details/7941585

PocketSphinx语音识别系统的编译、安装和使用:

http://blog.csdn.net/zouxy09/article/details/7942784

PocketSphinx语音识别系统语言模型的训练和声学模型的改进:

http://blog.csdn.net/zouxy09/article/details/7949126

PocketSphinx语音识别系统声学模型的训练与使用

http://blog.csdn.net/zouxy09/article/details/7962382

 

        本文主要实现PocketSphinx语音识别系统的编程使用,主要分两个方面,一个是编程解码语音文件(主要参考CMU sphinxwikihttp://cmusphinx.sourceforge.net/wiki/),二是编程识别麦克风的语音(主要参考PocketSphinx源码包里的pocketsphinx.c文件)。对于后面加入我的人机交互系统的话,采用的是识别麦克风的语音的编程,具体使用时还需要对其进行精简。

 

一、编程解码语音文件

1、编程:

[cpp]  view plain copy
  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.     //1、初始化:创建一个配置对象 cmd_ln_t *  
  14.     //cmd_ln_init函数第一个参数是我们需要更新的上一个配置,因为这里是初次创建,所以传入NULL;  
  15.     //第二个参数是一个定义参数的数组,如果使用的是标准配置的参数集的话可以通过调用ps_args()去获得。  
  16.     //第三个参数是是一个标志,它决定了参数的解释是否严格,如果为TRUE,那么遇到重复的或者未知的参  
  17.     //数,将会导致解释失败;  
  18.     //MODELDIR这个宏,指定了模型的路径,包括声学模型,语言模型和字典三个文件,是由gcc命令行传入,  
  19.     //我们通过pkg-config工具从PocketSphinx的配置中去获得这个modeldir变量  
  20.     config = cmd_ln_init(NULL, ps_args(), TRUE,  
  21.                  "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k",  
  22.                  "-lm", MODELDIR "/lm/en/turtle.DMP",  
  23.                  "-dict", MODELDIR "/lm/en/turtle.dic",  
  24.                  NULL);  
  25.     if (config == NULL)  
  26.         return 1;  
  27.       
  28.     //2、初始化解码器(语言识别就是一个解码过程,通俗的将就是将你说的话解码成对应的文字串)  
  29.     ps = ps_init(config);  
  30.     if (ps == NULL)  
  31.         return 1;  
  32.   
  33.     //3、解码文件流  
  34.     //因为音频输入接口(麦克风)受到一些特定平台的影响,不利用我们演示,所以我们通过解码音频文件流  
  35.     //来演示PocketSphinx API的用法,goforward.raw是一个包含了一些诸如“go forward ten meters”等用来  
  36.     //控制机器人的短语(指令)的音频文件,其在test/data/goforward.raw。把它复制到当前目录  
  37.     fh = fopen("/dev/input/event14""rb");  
  38.     if (fh == NULL) {  
  39.         perror("Failed to open goforward.raw");  
  40.         return 1;  
  41.     }  
  42.       
  43.     //4、使用ps_decode_raw()进行解码  
  44.       
  45.     rv = ps_decode_raw(ps, fh, NULL, -1);  
  46.     if (rv < 0)  
  47.         return 1;  
  48.       
  49.     //5、得到解码的结果(概率最大的字串) hypothesis  
  50.     hyp = ps_get_hyp(ps, &score, &uttid);  
  51.     if (hyp == NULL)  
  52.         return 1;  
  53.     printf("Recognized: %s\n", hyp);  
  54.   
  55.     //从内存中解码音频数据  
  56.     //现在我们将再次解码相同的文件,但是使用API从内存块中解码音频数据。在这种情况下,首先我们  
  57.     //需要使用ps_start_utt()开始说话:  
  58.     fseek(fh, 0, SEEK_SET);  
  59.       
  60.     rv = ps_start_utt(ps, NULL);  
  61.     if (rv < 0)  
  62.         return 1;  
  63.         while (!feof(fh)) {  
  64.     rv = ps_start_utt(ps, NULL);  
  65.         if (rv < 0)  
  66.                 return 1;  
  67.   
  68.         printf("ready:\n");  
  69.             size_t nsamp;  
  70.             nsamp = fread(buf, 2, 512, fh);  
  71.         printf("read:\n");  
  72.             //我们将每次从文件中读取512大小的样本,使用ps_process_raw()把它们放到解码器中:  
  73.             rv = ps_process_raw(ps, buf, nsamp, FALSE, FALSE);  
  74.         printf("process:\n");  
  75.         }  
  76.         //我们需要使用ps_end_utt()去标记说话的结尾处:  
  77.         rv = ps_end_utt(ps);  
  78.     if (rv < 0)  
  79.         return 1;  
  80.           
  81.     //以相同精确的方式运行来检索假设的字符串:  
  82.     hyp = ps_get_hyp(ps, &score, &uttid);  
  83.     if (hyp == NULL)  
  84.         return 1;  
  85.     printf("Recognized: %s\n", hyp);  
  86.     }  
  87.     //6、清理工作:使用ps_free()释放使用ps_init()返回的对象,不用释放配置对象。  
  88.     fclose(fh);  
  89.         ps_free(ps);  
  90.     return 0;  
  91. }  


 

 

2、编译:

编译方法:

gcc -o test_ps test_ps.c \

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

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

//gcc-D选项,指定宏定义,如-Dmacro=defn   相当于C语言中的#define macro=defn那么上面就表示在test_ps.c文件中,新加入一个宏定义:

#define MODELDIR=\"`pkg-config --variable=modeldir pocketsphinx`\"

\表示转义符,把“号转义。

         这么做是为什么呢?因为程序中需要指定MODELDIR这个变量,但是因为不同的使用者,这个变量不一样,没办法指定死一个路径,所以只能放在编译时,让用户去根据自己的情况来指定。

 

pkg-config工具可以获得一个库的编译和连接等信息;

#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

二、编程解码麦克风的录音

1、编程

       麦克风录音数据的获得主要是用sphinxbase封装了alsa的接口来实现。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <sys/types.h>  
  4. #include <sys/time.h>  
  5. #include <signal.h>  
  6. #include <setjmp.h>  
  7.   
  8. #include <sphinxbase/err.h>  
  9. //generic live audio interface for recording and playback  
  10. #include <sphinxbase/ad.h>  
  11. #include <sphinxbase/cont_ad.h>  
  12.   
  13. #include "pocketsphinx.h"  
  14.   
  15. static ps_decoder_t *ps;  
  16. static cmd_ln_t *config;  
  17.   
  18. static void print_word_times(int32 start)  
  19. {  
  20.     ps_seg_t *iter = ps_seg_iter(ps, NULL);  
  21.     while (iter != NULL)   
  22.     {  
  23.         int32 sf, ef, pprob;  
  24.         float conf;  
  25.           
  26.         ps_seg_frames (iter, &sf, &ef);  
  27.         pprob = ps_seg_prob (iter, NULL, NULL, NULL);  
  28.         conf = logmath_exp(ps_get_logmath(ps), pprob);  
  29.         printf ("%s %f %f %f\n", ps_seg_word (iter), (sf + start) / 100.0, (ef + start) / 100.0, conf);  
  30.         iter = ps_seg_next (iter);  
  31.     }  
  32. }  
  33.   
  34. /* Sleep for specified msec */  
  35. static void sleep_msec(int32 ms)  
  36. {  
  37.     struct timeval tmo;  
  38.   
  39.     tmo.tv_sec = 0;  
  40.     tmo.tv_usec = ms * 1000;  
  41.   
  42.     select(0, NULL, NULL, NULL, &tmo);  
  43. }  
  44.   
  45. /* 
  46.  * Main utterance processing loop: 
  47.  *     for (;;) { 
  48.  *     wait for start of next utterance; 
  49.  *     decode utterance until silence of at least 1 sec observed; 
  50.  *     print utterance result; 
  51.  *     } 
  52.  */  
  53. static void recognize_from_microphone()  
  54. {  
  55.     ad_rec_t *ad;  
  56.     int16 adbuf[4096];  
  57.     int32 k, ts, rem;  
  58.     char const *hyp;  
  59.     char const *uttid;  
  60.     cont_ad_t *cont;  
  61.     char word[256];  
  62.   
  63.     if ((ad = ad_open_dev(cmd_ln_str_r(config, "-adcdev"),  
  64.                           (int)cmd_ln_float32_r(config, "-samprate"))) == NULL)  
  65.         E_FATAL("Failed top open audio device\n");  
  66.   
  67.     /* Initialize continuous listening module */  
  68.     if ((cont = cont_ad_init(ad, ad_read)) == NULL)  
  69.         E_FATAL("Failed to initialize voice activity detection\n");  
  70.     if (ad_start_rec(ad) < 0)  
  71.         E_FATAL("Failed to start recording\n");  
  72.     if (cont_ad_calib(cont) < 0)  
  73.         E_FATAL("Failed to calibrate voice activity detection\n");  
  74.   
  75.     for (;;) {  
  76.         /* Indicate listening for next utterance */  
  77.         printf("READY....\n");  
  78.         fflush(stdout);  
  79.         fflush(stderr);  
  80.   
  81.         /* Wait data for next utterance */  
  82.         while ((k = cont_ad_read(cont, adbuf, 4096)) == 0)  
  83.             sleep_msec(100);  
  84.   
  85.         if (k < 0)  
  86.             E_FATAL("Failed to read audio\n");  
  87.   
  88.         /* 
  89.          * Non-zero amount of data received; start recognition of new utterance. 
  90.          * NULL argument to uttproc_begin_utt => automatic generation of utterance-id. 
  91.          */  
  92.         if (ps_start_utt(ps, NULL) < 0)  
  93.             E_FATAL("Failed to start utterance\n");  
  94.         ps_process_raw(ps, adbuf, k, FALSE, FALSE);  
  95.         printf("Listening...\n");  
  96.         fflush(stdout);  
  97.   
  98.         /* Note timestamp for this first block of data */  
  99.         ts = cont->read_ts;  
  100.   
  101.         /* Decode utterance until end (marked by a "long" silence, >1sec) */  
  102.         for (;;) {  
  103.             /* Read non-silence audio data, if any, from continuous listening module */  
  104.             if ((k = cont_ad_read(cont, adbuf, 4096)) < 0)  
  105.                 E_FATAL("Failed to read audio\n");  
  106.             if (k == 0) {  
  107.                 /* 
  108.                  * No speech data available; check current timestamp with most recent 
  109.                  * speech to see if more than 1 sec elapsed.  If so, end of utterance. 
  110.                  */  
  111.                 if ((cont->read_ts - ts) > DEFAULT_SAMPLES_PER_SEC)  
  112.                     break;  
  113.             }  
  114.             else {  
  115.                 /* New speech data received; note current timestamp */  
  116.                 ts = cont->read_ts;  
  117.             }  
  118.   
  119.             /* 
  120.              * Decode whatever data was read above. 
  121.              */  
  122.             rem = ps_process_raw(ps, adbuf, k, FALSE, FALSE);  
  123.   
  124.             /* If no work to be done, sleep a bit */  
  125.             if ((rem == 0) && (k == 0))  
  126.                 sleep_msec(20);  
  127.         }  
  128.   
  129.         /* 
  130.          * Utterance ended; flush any accumulated, unprocessed A/D data and stop 
  131.          * listening until current utterance completely decoded 
  132.          */  
  133.         ad_stop_rec(ad);  
  134.         while (ad_read(ad, adbuf, 4096) >= 0);  
  135.         cont_ad_reset(cont);  
  136.   
  137.         printf("Stopped listening, please wait...\n");  
  138.         fflush(stdout);  
  139.         /* Finish decoding, obtain and print result */  
  140.         ps_end_utt(ps);  
  141.         hyp = ps_get_hyp(ps, NULL, &uttid);  
  142.         printf("%s: %s\n", uttid, hyp);  
  143.         fflush(stdout);  
  144.   
  145.         /* Exit if the first word spoken was GOODBYE */  
  146.         if (hyp) {  
  147.             sscanf(hyp, "%s", word);  
  148.             if (strcmp(word, "goodbye") == 0)  
  149.                 break;  
  150.         }  
  151.   
  152.         /* Resume A/D recording for next utterance */  
  153.         if (ad_start_rec(ad) < 0)  
  154.             E_FATAL("Failed to start recording\n");  
  155.     }  
  156.   
  157.     cont_ad_close(cont);  
  158.     ad_close(ad);  
  159. }  
  160.   
  161. static jmp_buf jbuf;  
  162. static void sighandler(int signo)  
  163. {  
  164.     longjmp(jbuf, 1);  
  165. }  
  166.   
  167. int main(int argc, char *argv[])  
  168. {  
  169.       
  170.     config = cmd_ln_init(NULL, ps_args(), TRUE,  
  171.                  "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k",  
  172.                  "-lm", MODELDIR "/lm/en/turtle.DMP",  
  173.                  "-dict", MODELDIR "/lm/en/turtle.dic",  
  174.                  NULL);  
  175.     if (config == NULL)  
  176.         return 1;  
  177.       
  178.     ps = ps_init(config);  
  179.     if (ps == NULL)  
  180.         return 1;  
  181.   
  182.     signal(SIGINT, &sighandler);  
  183.     if (setjmp(jbuf) == 0)   
  184.         recognize_from_microphone();  
  185.       
  186.         ps_free(ps);  
  187.     return 0;  
  188. }  

 

2、编译

1.2一样。

 

       至于说后面把PocketSphinx语音识别系统加入我的人机交互系统这个阶段,因为感觉这个系统本身的识别率不是很高,自己做了适应和重新训练声学和语言模型后,提升还是有限,暂时实用性还不是很强,所以暂时搁置下,看能不能通过其他方法去改进目前的状态。希望有牛人指导下。另外,由于开学了,需要上课,所以后续的进程可能会稍微减慢,不过依然期待各位多多交流!呵呵

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值