文章目录
- 前言
- 一、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
#endif
static 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");
//china
ps_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);
}
else
break;
} 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是为了满足低资源消耗,等实际测试后再重新记录到这篇博客里面吧
如果对您有所帮助,请帮忙点个赞吧!