文章目录
- 前言
- 一、pocketsphinx的介绍
- 二、ubuntu下编译
- 三、使用示例
- 1.模型选择
- 2.代码示例
- 3.自定义字典
- 四、交叉编译
- 总结
前言
由于工作需要语音识别的功能,环境是在linux arm版上,所以想先在ubuntu上跑起来看一看,就找了一下语音识别的开源框架,选中了很多框架可以看编译vosk那篇文章,现在一一试验一下。
网上对于pocketsphinx的介绍都比较老了,本篇博客将会在ubuntu上进行pocketsphinx编译使用,并且进行交叉编译。
|版本声明:山河君,未经博主允许,禁止转载
一、pocketsphinx的介绍
PocketSphinx是一款卡内基梅隆大学的开源大型词汇、独立于说话人的连续语音识别引擎。
对于接下来的编译使用,你需要知道:
- 它是一个离线语音识别系统
- 不再依赖SphinxBase ,所以对于网上文章出现调用
cmd_ln_init
这种接口的都是比较老的文章,某一天可能这篇博客也会变老 - pocketsphinx当前只有社区维护了,如果对于开源项目更新速度有要求的,不建议再使用它了。
- 有几个关键网址需要知道: pocketsphinx源码下载地址,通用模型下载地址,自定义模型库工具地址
- pocketsphinx支持自定义词典,针对关键词进行识别
- pocketsphinx依赖的模型库非常重要的文件:HMM:描述音频信号的模型,基于音素的发音特征;
- pocketsphinx依赖的模型库非常重要的文件: Dict:将单词映射到其音素发音的字典文件
- pocketsphinx依赖的模型库非常重要的文件: LM:描述单词序列概率的语言模型,帮助识别上下文关系
二、ubuntu下编译
sudo apt-get install build-essential cmake bison flex libpulse-dev python3-dev
git clone https://github.com/cmusphinx/pocketsphinx.git
cd pocketsphinx
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/install
make
make install
在安装路径下出现表示成功
- bin:示例程序
- build:中间文件,不用管
- include:头文件
- lib:静态库
- share:里面包含一个英文的通用模型
三、使用示例
1.模型选择
可以选择使用自带的也就是上文中share文件夹包含的通用模型
如果想使用中文模型需要在通用模型下载地址下载,选择中文模型
模型解压后
2.代码示例
代码如下,我使用了麦克风的声音,所以会用到sox插件,这个读者可以自行更改:
#include <pocketsphinx.h>
#include <signal.h>static int global_done = 0;
static void
catch_sig(int signum)
{(void)signum;global_done = 1;
}#ifdef WIN32
#define popen _popen
#define pclose _pclose
#endifstatic FILE *
popen_sox(int sample_rate)
{char *soxcmd;int len;FILE *sox;
#define SOXCMD "sox -q -r %d -c 1 -b 16 -e signed-integer -d -t raw -"len = snprintf(NULL, 0, SOXCMD, sample_rate);if ((soxcmd = (char*)malloc(len + 1)) == NULL)E_FATAL_SYSTEM("Failed to allocate string");if (snprintf(soxcmd, len + 1, SOXCMD, sample_rate) != len)E_FATAL_SYSTEM("snprintf() failed");if ((sox = popen(soxcmd, "r")) == NULL)E_FATAL_SYSTEM("Failed to popen(%s)", soxcmd);free(soxcmd);return sox;
}int
main(int argc, char *argv[])
{ps_decoder_t *decoder;ps_config_t *config;ps_endpointer_t *ep;FILE *sox;short *frame;size_t frame_size;(void)argc; (void)argv;config = ps_config_init(NULL);ps_default_search_args(config);//en// ps_config_set_str(config, "dict", "/home/aaron/workplace/audioread/pocketsphinx/build/share/pocketsphinx/model/en-us/cmudict-en-us.dict");// ps_config_set_str(config, "lm", "/home/aaron/workplace/audioread/pocketsphinx/build/share/pocketsphinx/model/en-us/en-us.lm.bin");//chinaps_config_set_str(config, "hmm", "/home/aaron/workplace/audioread/ceshi/pocketsphinx/pocketsphinxtest/third/cmusphinx/zh_cn.cd_cont_5000");ps_config_set_str(config, "dict", "/home/aaron/workplace/audioread/ceshi/pocketsphinx/pocketsphinxtest/third/cmusphinx/zh_cn.dic");ps_config_set_str(config, "lm", "/home/aaron/workplace/audioread/ceshi/pocketsphinx/pocketsphinxtest/third/cmusphinx/zh_cn.lm.bin");if ((decoder = ps_init(config)) == NULL)E_FATAL("PocketSphinx decoder init failed\n");if ((ep = ps_endpointer_init(0, 0.0, (ps_vad_mode_t)0, 0, 0)) == NULL)E_FATAL("PocketSphinx endpointer init failed\n");sox = popen_sox(ps_endpointer_sample_rate(ep));frame_size = ps_endpointer_frame_size(ep);if ((frame = (short int *)malloc(frame_size * sizeof(frame[0]))) == NULL)E_FATAL_SYSTEM("Failed to allocate frame");if (signal(SIGINT, catch_sig) == SIG_ERR)E_FATAL_SYSTEM("Failed to set SIGINT handler");while (!global_done) {const int16 *speech;int prev_in_speech = ps_endpointer_in_speech(ep);size_t len, end_samples;if ((len = fread(frame, sizeof(frame[0]),frame_size, sox)) != frame_size) {if (len > 0) {speech = ps_endpointer_end_stream(ep, frame,frame_size,&end_samples);}elsebreak;} else {speech = ps_endpointer_process(ep, frame);}if (speech != NULL) {const char *hyp;if (!prev_in_speech) {fprintf(stderr, "Speech start at %.2f\n",ps_endpointer_speech_start(ep));ps_start_utt(decoder);}if (ps_process_raw(decoder, speech, frame_size, FALSE, FALSE) < 0)E_FATAL("ps_process_raw() failed\n");if ((hyp = ps_get_hyp(decoder, NULL)) != NULL)fprintf(stderr, "PARTIAL RESULT: %s\n", hyp);if (!ps_endpointer_in_speech(ep)) {fprintf(stderr, "Speech end at %.2f\n",ps_endpointer_speech_end(ep));ps_end_utt(decoder);if ((hyp = ps_get_hyp(decoder, NULL)) != NULL)printf("%s\n", hyp);}}}free(frame);if (pclose(sox) < 0)E_ERROR_SYSTEM("Failed to pclose(sox)");ps_endpointer_free(ep);ps_free(decoder);ps_config_free(config);return 0;
}
结果如下:
3.自定义字典
- 打开一个txt,输入想指定的词典,尽量多几行,单行不识别
- 通过自定义模型库工具地址网址进行上传,选择文件后点击comple knowledge base按钮
- 点击comple knowledge base按钮后,下载对应的包解压
- 解压后,可以看到存在
dic
字典,再把后缀为.lm
文件重命名为.lm.bin
- 打开
0047.dic
和之前的通用模型zh_cn.dic
,对照zh_cn.dic
在0047.dic
中添加英译,如果不存在就搜单个字音译,这个规律很好找,数字代表的声调
- 替换到模型里,指定当前的词典,那么只会针对词典里的词进行识别了
四、交叉编译
交叉工具选择aarch64
# aarch64_toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
set(CMAKE_ASM_COMPILER aarch64-linux-gnu-as)
set(CMAKE_LINKER aarch64-linux-gnu-ld)
set(CMAKE_STRIP aarch64-linux-gnu-strip)
set(CMAKE_OBJCOPY aarch64-linux-gnu-objcopy)
set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu)
set(CMAKE_OBJDUMP aarch64-linux-gnu-objdump)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu)
这一行比较重要,我在交叉编译时发现找不到对应的libm库,加了这一行才找到
cmake .. -DCMAKE_TOOLCHAIN_FILE=/toolchain.cmake -DCMAKE_INSTALL_PREFIX=./ -DCMAKE_EXE_LINKER_FLAGS="-lm"
make
make install
结果:
总结
本来想把其他几个开源语音识别引擎也初步记录一下的,看以后有没有时间吧,使用pocketsphinx是为了满足低资源消耗,等实际测试后再重新记录到这篇博客里面吧
如果对您有所帮助,请帮忙点个赞吧!