ubuntu下使用pocketsphinx进行语音识别(包含交叉编译)

文章目录


前言

由于工作需要语音识别的功能,环境是在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下编译

bash 复制代码
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插件,这个读者可以自行更改:

c 复制代码
#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

bash 复制代码
# 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库,加了这一行才找到

bash 复制代码
cmake .. -DCMAKE_TOOLCHAIN_FILE=/toolchain.cmake -DCMAKE_INSTALL_PREFIX=./ -DCMAKE_EXE_LINKER_FLAGS="-lm"
make
make install

结果:


总结

本来想把其他几个开源语音识别引擎也初步记录一下的,看以后有没有时间吧,使用pocketsphinx是为了满足低资源消耗,等实际测试后再重新记录到这篇博客里面吧

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

相关推荐
脱了格子衬衫12 分钟前
linux安装ansible
linux·运维·ansible
小丑西瓜66620 分钟前
MySQL库操作
linux·服务器·数据库·mysql
小珑也要变强3 小时前
shell脚本基本概念讲解
linux·运维
爱吃喵的鲤鱼4 小时前
linux 用C语言编写自己的myshell
linux·运维·服务器·c语言·算法
矛取矛求7 小时前
Linux如何更优质调节系统性能
linux
内核程序员kevin8 小时前
在Linux环境下使用Docker打包和发布.NET程序并配合MySQL部署
linux·mysql·docker·.net
kayotin9 小时前
Wordpress博客配置2024
linux·mysql·docker
Ztiddler10 小时前
【Linux Shell命令-不定期更新】
linux·运维·服务器·ssh
小小不董10 小时前
Oracle OCP认证考试考点详解082系列16
linux·运维·服务器·数据库·oracle·dba
a1denzzz10 小时前
Linux系统的网络设置
linux·服务器·网络