利用PocketSphinx在Windows上搭建一个语言识别应用

利用PocketSphinx在Windows上搭建一个语言识别应用

  • 准备工作
  • PocketSphinx简介
  • PocketSphinx示例
    • VS安装C++开发包
    • 创建一个C++工程
    • 工程配置
      • 代码
      • 配置
        • 添加include path
        • 静态链接库(lib)配置
        • 动态链接库拷贝
      • 代码分析
      • 运行

准备工作

在搭建应用之前需要以下准备工作:

  • 根据PocketSphinx安装的步骤,下载安装PocketSphinx;
  • visual studio,在本文中我使用的是visual studio 2017,你可以使用visual studio 2012及以上;
  • PocketSphinx使用c编写的,所以需要基本的c或c++编程语言知识;
  • visual studio需要支持c++编写;
    既然准备好了,那我们就开始啦。

PocketSphinx简介

Pocketsphinx API旨在简化应用程序中语音识别器功能的使用,它具有一下特点:
1.由于使用抽象类型,它在源代码和二进制兼容性方面很可能保持稳定;
2.它是完全可重入的,因此在同一个过程中有多个解码器是没有问题的;
3.它允许大幅减少代码占用空间,而且支持适度但显著减少内存消耗。

PocketSphinx示例

这个小程序的基本功能是:读取一个wav语音文件,利用pocketSphinx API将该语音文件转化为文字。

VS安装C++开发包

由于我们需要用Visual Studio 2017编写c++程序,因此需要为VS安装C++语言包。

  • 打开visual studio,在菜单Tools下选择get tools and features.
    利用PocketSphinx在Windows上搭建一个语言识别应用_第1张图片
    安装标注的C++包
    利用PocketSphinx在Windows上搭建一个语言识别应用_第2张图片
    安装完成后,进行下一步。

创建一个C++工程

利用PocketSphinx在Windows上搭建一个语言识别应用_第3张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第4张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第5张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第6张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第7张图片
新工程创建完毕,在正式开始写代码之前,我们需要配置include路径以及linker(链接)路径,从而使得我们的程序可以引用pocketsphinx。

工程配置

代码

#include 

#define MODELDIR "D:/sphinx/pocketsphinx/model"

int main(int argc, char *argv[]) {
	ps_decoder_t *ps = NULL;
	cmd_ln_t *config = NULL;

	FILE *fh;
	char const *hyp, *uttid;
	int16 buf[512];
	int rv;
	int32 score;

	config = cmd_ln_init(NULL, ps_args(), TRUE,
		"-hmm", MODELDIR "/en-us/en-us",
		"-lm", MODELDIR "/en-us/en-us.lm.bin",
		"-dict", MODELDIR "/en-us/cmudict-en-us.dict",
		NULL);

	if (config == NULL) {
		fprintf(stderr, "Failed to create config object, see log for details\n");
		return -1;
	}

	ps = ps_init(config);

	if (ps == NULL) {
		fprintf(stderr, "Failed to create recognizer, see log for details\n");
		return -1;
	}

	fh = fopen("goforward.raw", "rb");
	if (fh == NULL) {
		fprintf(stderr, "Unable to open input file goforward.raw\n");
		return -1;
	}

	rv = ps_start_utt(ps);
	while (!feof(fh)) {
		size_t nsamp;
		nsamp = fread(buf, 2, 512, fh);
		rv = ps_process_raw(ps, buf, nsamp, FALSE, FALSE);
	}

	rv = ps_end_utt(ps);
	hyp = ps_get_hyp(ps, &score);
	printf("Recognized: %s\n", hyp);

	fclose(fh);
	ps_free(ps);
	cmd_ln_free_r(config);

	return 0;
}

配置

当你在Main.cpp中输入以上代码时,你会发现pocketsphinx.h找不到:
利用PocketSphinx在Windows上搭建一个语言识别应用_第8张图片
这是因为要想找到相关的头文件,需要修改项目中的include path。每个动态链接库编译成功后,都会附带一个include folder,用于给调用该动态链接库的项目使用,include文件夹里面包含了需要用到的头文件。所以我们的第一步是添加include path到该项目中。

添加include path

pocketsphinx的include文件夹路径是:
利用PocketSphinx在Windows上搭建一个语言识别应用_第9张图片
sphinxbase的include文件夹路径d:\sphinx\sphinxbase\include,进入该文件夹,还有几个更细节的子文件夹:
利用PocketSphinx在Windows上搭建一个语言识别应用_第10张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第11张图片
右击项目名称,选择properties:
利用PocketSphinx在Windows上搭建一个语言识别应用_第12张图片
在properties窗口中的VC++ Directories里面,选择include directories,并点击下拉菜单,选择edit:
利用PocketSphinx在Windows上搭建一个语言识别应用_第13张图片
添加d:\sphinx\pocketsphinx\include到include directories中,点击ok关闭该对话框。
利用PocketSphinx在Windows上搭建一个语言识别应用_第14张图片
之后查看代码,就可以发现,pocketsphinx.h可以找到了,但是还是有提示某些类找不到,比如cmd_ln_t,这是由于cmd_ln_t的头文件不是在pocketsphinx的include文件夹下,而是在sphinxbase include文件夹下,所以需要添加sphinxbase include文件夹。
利用PocketSphinx在Windows上搭建一个语言识别应用_第15张图片
添加sphinxbase的include文件夹,在这一步中不能只包含根目录的include文件夹,而且还要包含具体的子文件夹,因为我们是在window平台上使用,所以我们包含下面两个文件夹:
利用PocketSphinx在Windows上搭建一个语言识别应用_第16张图片
为什么我们要包含根目录,而不是直接包含子目录就可以了呢,那是因为在pocketsphinx的头文件引用sphinxbase下的include文件时,使用了相对路径,例如在pocketsphinx.h包含了这样一段代码:

#include 
#include 
#include 
#include 

它使用了某个路径下的sphinxbase相对路径,所以必须包含sphinxbase下的include根目录,编译时才能找到该文件。
添加之后,我们就可以看到,我们的代码没有语法错误了。
那么是否意味着我们的代码可以编译了呢,那么让我们来试一下:
结果我们遇到了这样一个错误:
在这里插入图片描述
这是由于secure的规则不同造成的,为了避免修改代码,我们将在项目中定义_CRT_SECURE_NO_WARNINGS,从而让项目忽略这个规则的错误。现在继续打开项目的properties,添加宏变量_CRT_SECURE_NO_WARNINGS:
利用PocketSphinx在Windows上搭建一个语言识别应用_第17张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第18张图片
重新编译,现在之前的错误没有了,又遇到了新的编译错误:
利用PocketSphinx在Windows上搭建一个语言识别应用_第19张图片
这个错误是为什么呢?这个跟c++生成一个可执行文件的过程有关,下面简单介绍一下这个过程:

  • 预处理:主要是做一些代码文本的替换工作
  • 编译:把预处理完的文件进行一系列词法分析(lex)、语法分析(yacc)、语义分析及优化后生成汇编代码,这个过程是程序构建的核心部分
  • 汇编:汇编代码->机器指令
  • 链接:这里讲的链接,严格说应该叫静态链接,在程序经过预处理、编译和汇编后,每个源文件会生成中间文件,叫做obj文件,这个文件并不包括它所引用的其他头文件,所以在最终生成可执行文件之前,需要将该obj文件与其他目标文件(比如程序中调用的其他的静态链接库)整合拼接起来,这个过程就是链接
  • 生成可执行文件
    而我们之所以遇到之前的错误,就是因为“链接”这一步出现了问题,在静态链接时,需要指定引用动态链接库的静态链接库的位置。 下面我们就来配置这一环节。

静态链接库(lib)配置

首先我们需要找到pocketsphinx的lib文件在哪儿呢?在D:\sphinx\pocketsphinx\bin\Release\Win32文件夹下,由于该处已经包含pocketsphinx.lib和sphinxbase.lib,所以只需要添加这一个文件夹就可以了:
利用PocketSphinx在Windows上搭建一个语言识别应用_第20张图片
打开项目的properties,在VC++ Directories下面配置或者在Linker下面配置,我们将在linker下面配置,在配置时需要配置两个位置,一个是配置Additional Library Directories,也就是说lib的文件夹位置,另一个是配置需要用到哪些lib,完成后关闭对话框:
利用PocketSphinx在Windows上搭建一个语言识别应用_第21张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第22张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第23张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第24张图片
利用PocketSphinx在Windows上搭建一个语言识别应用_第25张图片
配置完成后重新编译该项目:
Yeah,成功!
利用PocketSphinx在Windows上搭建一个语言识别应用_第26张图片
那是否意味着我们完成了呢?当然不是。。。我们还需要最重要的一步。

动态链接库拷贝

在程序运行时,需要引用响应的动态链接库,那么我们需要将程序用到的动态链接库在编译时拷贝到最终的可执行文件所在的文件夹,否则就会遇到执行时的错误。
我们需要拷贝两个dll文件,一个是pocketsphinx.dll,另一个是spinxbase.dll。
利用PocketSphinx在Windows上搭建一个语言识别应用_第27张图片
输入命令:xcopy /y /d “D:\sphinx\pocketsphinx\bin\Release\Win32*” “$(OutDir)”
利用PocketSphinx在Windows上搭建一个语言识别应用_第28张图片
点击ok关闭对话框。

代码分析

代码的基本逻辑是:

  • 创建一个配置对象,cmd_ln_t,设置声学模型,语言模型和语音学字典;
  • 初始化一个ps_decoder_t,这是真正的语音解析器;
  • 启动语音解析器,将音频文件goforward.raw输入到解析器中进行解析;
  • 最终得到最可能的解析结果
    在这里我们用到了一个音频文件goforward.raw, 你可以在D:\sphinx\pocketsphinx\test\data中找到该文件,并将其添加到项目中。
    并配置build post event,从而将goforward.raw输出到output folder中:
    利用PocketSphinx在Windows上搭建一个语言识别应用_第29张图片

运行

利用PocketSphinx在Windows上搭建一个语言识别应用_第30张图片

你可能感兴趣的:(利用PocketSphinx在Windows上搭建一个语言识别应用)