前言

由于工作需要语音识别的功能,环境是在linux arm版上,所以想先在ubuntu上跑起来看一看,就找了一下语音识别的开源框架,选中了很多框架可以看编译vosk那篇文章,现在一一试验一下。

网上对于pocketsphinx的介绍都比较老了,本篇博客将会在ubuntu上进行pocketsphinx编译使用,并且进行交叉编译。

|版本声明:山河君,未经博主允许,禁止转载


一、pocketsphinx的介绍

PocketSphinx是一款卡内基梅隆大学的开源大型词汇、独立于说话人的连续语音识别引擎。

对于接下来的编译使用,你需要知道:

  1. 它是一个离线语音识别系统
  2. 不再依赖SphinxBase ,所以对于网上文章出现调用cmd_ln_init这种接口的都是比较老的文章,某一天可能这篇博客也会变老
  3. pocketsphinx当前只有社区维护了,如果对于开源项目更新速度有要求的,不建议再使用它了。
  4. 有几个关键网址需要知道: pocketsphinx源码下载地址通用模型下载地址自定义模型库工具地址
  5. pocketsphinx支持自定义词典,针对关键词进行识别
  6. pocketsphinx依赖的模型库非常重要的文件:HMM:描述音频信号的模型,基于音素的发音特征;
  7. pocketsphinx依赖的模型库非常重要的文件: Dict:将单词映射到其音素发音的字典文件
  8. 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.dic0047.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是为了满足低资源消耗,等实际测试后再重新记录到这篇博客里面吧

如果对您有所帮助,请帮忙点个赞吧!

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐