2016-10-07 21:18:45 sac761 阅读数 21676

本项目做出的产品是一个Windows下的增强现实系统,系统很庞大,产品功能已经基本完善,考虑到给用户带来更好的体验,故综合评估后采用讯飞语音识别方案进行嫁接。

项目介绍:

1)打开系统时启动语音识别,检测到用户说出关键词(如:上一步,下一步,结束等)时,系统自动进行相应的操作;

2)不需要按任何按键进行连续的语音识别控制,延迟为2秒左右;

3)可以识别词语,句子,中文,英文数字字母通吃,不限语速。并且语句结束判断机制很智能;

3)离线!离线!现在做一个基于windows的离线的语音识别系统在网络上还真没谁,讯飞自己也还没有推出这款SDK,我是在讯飞的离线命令词识别SDK开发包上开发出的介于两者之间功能的系统。

为什么用讯飞:

之前使用过语音识别开发版,用驻极体采集声音,通过串口传输信号来进行识别,只能讲开发版只适合用来做个课程设计啥的玩玩,做产品还是太LOW,识别率地下并且识别范围窄,貌似只能识别数字字母;之后调查过汉语语音识别库如Sphinx,Julius,百度语音等。去网上问,很多人推荐这些方案的,我没试过,不过一个SDK也只有自己正真开发过才知道好不好用强不强大,说的再牛逼也是在别人手上玩的转,到你这就不一定了。我用讯飞就是看上它的鲁棒,免费,毕竟是久经考验的平台,讯飞有一个开发者论坛,开发别人的SDK有个社区很重要,不然有问题没地方问。


项目开发经验与源码如下:

一、跑通讯飞离线命令词识别SDK

首先去讯飞官网下载相应SDK,要注册登录,绑定产品才能下载,下载后跑一跑给的demo,跑不通的话去讯飞的论坛找答案。

我用的demo是asr_record_demo,这个demo可以实现的功能是按下R键从mic中录制缓冲音频并按下S键后进行识别。

稍微看一看这个demo中的东西吧,把该删的东西删了,该修整的修整,玩转了demo才能进一步做移植。

二、文件分析与移植

把SDK包中的需要的.lib  .h  .c和所需要的其余文件拷贝到项目相应的文件夹去,最好是分个类,看起来比较清楚。它比较重要的几个文件有以下几个:

msc.lib   讯飞语音离线命令词识别所依赖的库(X64版本为msc_x64.lib)才15KB就能有如此强大的功能。

call.bnf    采用巴科斯范式语法规则的自定义语法库(call是根据自己需要命名的),用来编写语音识别过程中的语法规则,这个语法写的好语音识别更智能。

speech_recognizer.c  基于录音接口和MSC接口封装一个MIC录音识别的模块,SDK的主要文件

winrec.c  封装windows录音,Windows平台下SDK的主要文件


好了,既然demo已经知道怎么用了,把demo所依赖的所有文件和库照搬进自己的项目去,就可以在自己的项目中调用讯飞的函数了(注意头文件和库文件的路径问题)。

三、使用讲解

先看看我的语法文件

call.bnf:


巴科斯范式语法语法文件怎么写在讯飞的论坛里有很多资源自己去看吧,我写的比较简单,写得好的语法可以更加智能。


大致讲讲源码:

为了看起来简洁,我在speech_recognizer.h中做了一个类SR,把主文件中的一些函数定义和一些宏搬进去。

speech_recognizer.h:

class SR {
public:

	const char * ASR_RES_PATH = "fo|res/asr/common.jet";  //离线语法识别资源路径
#ifdef _WIN64
	const char * GRM_BUILD_PATH = "res/asr/GrmBuilld_x64";  //构建离线语法识别网络生成数据保存路径
#else
	const char * GRM_BUILD_PATH = "res/asr/GrmBuilld";  //构建离线语法识别网络生成数据保存路径
#endif
	const char * GRM_FILE = "call.bnf"; //构建离线识别语法网络所用的语法文件

	int build_grammar(UserData *udata);//构建语法
	int run_asr(UserData *udata);//启动引擎

};
speech_recognizer.c:

#pragma comment(lib,"../../lib/msc_x64.lib") //x64
#else
#pragma comment(lib,"XXXXXX/lib/msc.lib") //x86
#endif
这里的库目录要注意,用相对路径可能找不到文件,可以使用绝对路径

#ifdef _WIN64
<pre name="code" class="cpp">static int update_format_from_sessionparam(const char * session_para, WAVEFORMATEX *wavefmt)
{
	char *s;
	/*if ((s = strstr(session_para, "sample_rate"))) {
		if (s = strstr(s, "=")) {
			s = skip_space(s);
			if (s && *s) {
				wavefmt->nSamplesPerSec = atoi(s);
				wavefmt->nAvgBytesPerSec = wavefmt->nBlockAlign * wavefmt->nSamplesPerSec;
			}
		}
		else
			return -1;
	}
	else {
		return -1;
	}*/

	return 0;
}


如果加到讯飞提供的demo使用的是VS2010如果放到VS2015中就会出一些语法上的错,自己看着改一改,比如上面这个函数,是更新用户词典用的,我不需要但是又存在语法错误,就把它的内容直接注释掉得了。

我的项目的主文件中:

首先定义几个宏:

UserData asr_data;//语音识别用户配置
speech_rec asr;//麦克风输入存储结构体
SR sr;//语音识别实体
string SPEAKER="";//用于缓存语音识别内容
在程序初始化处配置如下:

openVoiceRecognizer = true;//语音识别开关
	if (openVoiceRecognizer)
	{
		const char *login_config = "appid = XXXXX"; //登录参数
		int ret = 0;


		ret = MSPLogin(NULL, NULL, login_config); //第一个参数为用户名,第二个参数为密码,传NULL即可,第三个参数是登录参数
		if (MSP_SUCCESS != ret) {
			printf("登录失败:%d\n", ret);
			openVoiceRecognizer = false;
		}


		memset(&asr_data, 0, sizeof(UserData));
		printf("构建离线识别语法网络...\n");
		ret = sr.build_grammar(&asr_data);  //第一次使用某语法进行识别,需要先构建语法网络,获取语法ID,之后使用此语法进行识别,无需再次构建
		if (MSP_SUCCESS != ret) {
			printf("构建语法调用失败!\n");
			openVoiceRecognizer = false;
		}


		while (1 != asr_data.build_fini)
			_sleep(300);
		if (MSP_SUCCESS != asr_data.errcode)
			_sleep(300);
		printf("离线识别语法网络构建完成,开始识别...\n");
		ret = sr.run_asr(&asr_data);//预启动语音识别引擎
	}
在初始化这里我修改了 sr.run_asr(&asr_data);这个函数,我把它调用的sr_start_listening(&asr);函数抽离出来,不让它启动识别引擎而只让它预启动,把所有结构体,变量先初始化待命。

void recognize_mic(const char* session_begin_params)  //根据自己项目需要写的语音识别预热函数
{
	int errcode;
	HANDLE helper_thread = NULL;

	struct speech_rec_notifier recnotifier = {
		on_result,
		on_speech_begin,
		on_speech_end
	};
	errcode = sr_init(&asr, session_begin_params, SR_MIC, DEFAULT_INPUT_DEVID, &recnotifier);
	if (errcode) {
		printf("speech recognizer init failed\n");
		return;
	}

	/*	while (1) {
			errcode = sr_start_listening(&asr);//我把它调用的sr_start_listening(&asr);函数抽离出来,不让它启动识别引擎而只让它预启动,把所有结构体,变量先初始化待命。
		}

	exit:
		sr_uninit(&asr);*/
}

int SR::run_asr(UserData *udata)
{
	char asr_params[MAX_PARAMS_LEN] = { NULL };
	const char *rec_rslt = NULL;
	const char *session_id = NULL;
	const char *asr_audiof = NULL;
	FILE *f_pcm = NULL;
	char *pcm_data = NULL;
	long pcm_count = 0;
	long pcm_size = 0;
	int last_audio = 0;
	int aud_stat = MSP_AUDIO_SAMPLE_CONTINUE;
	int ep_status = MSP_EP_LOOKING_FOR_SPEECH;
	int rec_status = MSP_REC_STATUS_INCOMPLETE;
	int rss_status = MSP_REC_STATUS_INCOMPLETE;
	int errcode = -1;
	int aud_src = 0;

	//离线语法识别参数设置
	_snprintf(asr_params, MAX_PARAMS_LEN - 1,         //<span style="font-family: Arial, Helvetica, sans-serif;">离线语法识别参数根据自己的需要进行更改</span>

		"engine_type = local, \
		asr_res_path = %s, sample_rate = %d, \
		grm_build_path = %s, local_grammar = %s, ",
		sr.ASR_RES_PATH,
		SAMPLE_RATE_16K,
		sr.GRM_BUILD_PATH,
		udata->grammar_id
		);

	recognize_mic(asr_params);
	return 0;
}
而后是三个语音识别的中间过程和结果处理的函数:

void on_result(const char *result, char is_last)   //根据自己的需要写结果处理
{
	char *p = "上一步";
	char *pq = "下一步";
	char *q = "扫频仪操作演示";
	char *end1 = "结束";
	char *end2 = "退出";
	if (strstr(result, p)) {
		SPEAKER = "上一步";	
	}
	else if (strstr(result, pq)) {
		SPEAKER = "下一步";
	}
	else if (strstr(result, q)) {
		SPEAKER = "扫频仪操作演示";
	}
	else if (strstr(result,end1)|| strstr(result, end2)) {
		SPEAKER = "退出";
	}
	cout << SPEAKER << endl;
}
void on_speech_begin()
{
	if (g_result)
	{
		free(g_result);
	}
	g_result = (char*)malloc(BUFFER_SIZE);
	g_buffersize = BUFFER_SIZE;
	memset(g_result, 0, g_buffersize);

	printf("Start Listening...\n");
}
void on_speech_end(int reason)
{
	if (reason == END_REASON_VAD_DETECT)
		printf("\nSpeaking done \n");
	else
		printf("\nRecognizer error %d\n", reason);
}
最后就是在自己项目哪里需要语音识别就在哪里抛出缓冲线程启动识别引擎:

if (openVoiceRecognizer) {
		
		sr_start_listening(&asr);//抛出缓冲线程进行语音识别

		if (SPEAKER=="下一步") {
			keyPressed(' ');
		}
		else if (SPEAKER == "上一步") {
			keyPressed('b');
		}
		else if (SPEAKER == "扫频仪操作演示") {
			keyPressed('1');
		}
		else if (SPEAKER=="退出") {
			std::exit(0);
		}
		SPEAKER = "";
	}

上面代码中的关键就是sr_start_listening(&asr);这个函数,前面也说了这是从run_asr()调用的方法中抽离出来的,抽离出来后run_asr()就变成了预热函数,只需在程序初始化的时候调用它后面的语音识别就不要重复调用了,节省资源。

必须要说说这个关键函数sr_start_listening(&asr);

这是讯飞这款SDK中不需要动的最后一个封装好的函数,里面的东西不要动,前面的东西配置好一调用它就可以进行语音识别了,这个函数中的东西是这款SDK的精华,实现过程很复杂不需要管,但是要记住它的几个特性:

1)一调用它就相当于抛出了一个带缓冲的新线程,这个线程独立进行语音的识别可以不干扰项目的主循环的进行。

2)这个线程寿命是自动的,程序一开始启动到这里调用这个函数后启动线程,当程序的主循环又回来这里不会重复启动这个线程,而是该线程识别完用户的语音判断语句结束机制触发后才待命,等待下一次循环的启动。这句话有些费解,用我的项目解释下:我的项目在update()函数中调用sr_start_listening(&asr); 我的update()函数每100毫秒循环一次,第一次循环启动这个函数,抛出线程进行语音识别,语音识别用了10秒结束,在这10秒过程中update()循环了100次,但是只启动该函数一次,第101次循环的时候就可以第二次启动该函数了,同时在上面代码片中我用SPEAKER转存的字符串的判断条件已经成立,就可以进行相应的操作了,在这里我触发了不同的按键来代替各种操作。

3)举个栗子,我在update()中可以在每一次循环时画一帧图片的方式实现一个视频的播放,而在这里面调用语音引擎sr_start_listening(&asr);,在引擎识别的过程中会不会中断视频的播放或者视频出现卡帧或迟滞呢?答案是不会,上面也解释了,这个函数抛出一个独立的线程,不影响主函数的循环。所以可以用这种方法实现用语音控制视频的播放:快进、后退、暂停、截屏、全屏、音量加大、切换到高清......是不是很酷!

上面的几个源码文件我打了个包,下载看可能更清楚:

http://download.csdn.net/detail/sac761/9647029

四、总结

我用这个方案实现了离线的语音控制系统,语音识别率达到百分之九十以上,而且词语句子中英文通吃,实时性强,系统鲁棒。

畅想一下用这个方法加方案开发这几个产品:

语音控制的媒体播放器,功能在上面也讲了,很酷的!

语音控制的PPT遥控器

语音控制的AR/VR系统

语音交互智能眼镜

.............





2020-02-18 16:43:13 weixin_44532659 阅读数 286

“智能客服+人工坐席”的新型客户服务模式,通过自动化的语音识别技术,降低客服中心的人力成本,提升客服中心的运营效率。

应用场景:客服质检、机器人外呼、语音导航

智能客服和领域非常相关,不同领域的话题各不相同,还有大量的领域词汇,所以需要根据不同领域来训练相应的语音识别模型。

客服语音识别的技术挑战:
1、有些客户普通话口音重:不同地域有不同的口音特点
2、自然风格说话:语速快、吐字不清、抢话叠字
3、电话信道、领域术语多:电话信道8Kh采样,音质差。不同行业有自己独特的领域术语
4、有些客户讲方言:中国有七大方言区、数十种方言

语音数据训练测试实验:
一、全领域客服测试
测试数据:涵盖金融、电信、教育、电商、房产等领域的客服语音
在这里插入图片描述
ASR1: “普通话朗读数据”训练所得模型
ASR1+2: ASR1基础上,增加“重口音普通话数据”
ASR1+2+3: ASR1+2基础上,增加“普通话自然对话数据”
ASR1+2+3+4: 在ASR1+2+3基础上,增加“实网客服语音数据”

结论:
只使用数据堂普通话朗读数据训练后,识别模型的字错率是54.8%,在叠加数据堂重口音普通话、普通话自然对话、实网客服语音后,字错率降到了12.5%.

二、金融领域客服测试
测试数据:金融领域的客服语音
在这里插入图片描述
ASR1: “普通话朗读数据”训练所得模型
ASR1+2: ASR1基础上,增加“重口音普通话数据”
ASR1+2+3: ASR1+2基础上,增加“普通话自然对话数据”
ASR1+2+3+4: 在ASR1+2+3基础上,增加“实网客服语音数据”

结论:
只使用数据堂普通话朗读数据训练后,识别模型的字错率是54.8%,在叠加数据堂重口音普通话、普通话自然对话、实网客服语音后,字错率降到了12.5%.

相关实验数据:

一、普通话朗读语音
1505小时普通话手机采集语音数据
在这里插入图片描述

849小时普通话家居交互手机语音数据
在这里插入图片描述

二、普通话自然对话语音

1000小时普通话多人自然对话语音数据
在这里插入图片描述
2000小时普通话两人自然对话语音数据
在这里插入图片描述

1420小时普通话自然语音手机采集数据
在这里插入图片描述

三、重口音普通话语音

1026小时重口音普通话手机采集语音数据
在这里插入图片描述

662小时重口音普通话手机采集语音数据
在这里插入图片描述

132小时重口音普通话手机采集语音数据
在这里插入图片描述

四、实网客服语音

2823小时普通话客服实网语音采集数据
在这里插入图片描述

555小时全领域客服实网语音采集数据
在这里插入图片描述

140小时电商客服普通话实网采集语音数据
在这里插入图片描述

五、方言语音

方言语音-朗读
在这里插入图片描述

方言语音-自然对话
在这里插入图片描述
https://www.datatang.com/dataset/all/1

2019-04-03 18:53:42 qq_43019717 阅读数 3269

大家好,时间过得真快,转眼进入到四月份了,语音测评君又给大家带来了新一期语音相关的测评报告。结合现在语音算法公司越来越多的情况,本次小君针对当前市场份额较大的几家算法公司,分别测试了语速对语音引擎识别结果的影响。这几家公司分别是科大讯飞,百度,思必驰信息科技和云知声信息科技有限公司。每个公司都有自己的开发平台,给广大语音开发爱好者提供的开源的开发接口,给大家提供了相关的SDK和开发文档。
本次测评主要是对比每家语音识别引擎对快中慢语速的处理,测试语音信息详情如下:
 音频编码格式:wav
 音频采样率:16000Hz
 文本字数:每条平均60字左右,共计615字。
 音频分类:分为快语速、普通语速、慢语速,共计30条音频,每类10条
 音频领域:歌曲、闲聊
正常情况下,不同人说话的语速是不一样的,有人说话快,有人说话慢。所以小君这次测试的出发点是站在人正常说话的角度考虑的,并没有仅仅是为了测试算法而去设置极限值。

展示一下文本样例:

  1. 这是一首唱给母亲听的歌曲,他曾经在综艺节目笑着谈起母亲逝世前的点滴,十分感人。毛不易的另外一首歌曲《消愁》的词沉浸着对生活的深切感悟,可以扎人心。
  2. 现在中国的男人比女人多那么多,可以说一定是有几千万是娶不到媳妇的。这绝对不是危言耸听,这就是事实,而且很可能有些男同胞已经感觉出来了。

语音文本的信息相信大家了解的差不多了,那让我们来看一下对比结果,来分析各引擎的优缺点吧。
(备注:以上测评结果仅基于本次验证集)

结果分析:基于本次验证集的数据对比分析,百度和科大讯飞的语音识别引擎在慢语速识别率较其他两个厂家存在一定的差距,百度慢语速语音识别率为46.50%,科大讯飞为75.11%,而另外两家的慢语速识别率分别达到了98.70%和95.45%。四家算法厂商在普通语速和快语速方面的识别率还是相当高的。
由于小君仅仅测试了音乐和闲聊两个领域,可能这两个领域并不是百度和讯飞的专长,如果想看更多领域的测评结果,您可以联系语音测评君,小君欢迎您随时关注和联系!

2020-03-22 13:15:00 u014365862 阅读数 180

 

http://sox.sourceforge.net/

时域重采样,同时改变语速与语调 使用波形相似重叠相加算法(WSOLA),只改变语速 频域拉伸与压缩,只改变语调

Kaldi学习经验:

http://kaldi-asr.org/

Kaldi学习—资料:

1. 官网:http://kaldi-asr.org/doc/
2. 好的blog (原理 或 正确的kaldi内容)
3. 源代码:https://github.com/kaldi-asr/kaldi

Kaldi学习—编程基础:

  1. Git (时常同步kaldi源码)

  2. Linux (推荐使用)

  3. Shell (if, for, here document....)& 一些功能强大的小命令(awk, find, sed, grep....)

  4. Perl 和 Python

  5. C++ (Google Style)

  6. (可能)Sun Grid Engine(SGE)

 

 

 

2020-03-09 16:34:43 weixin_44065323 阅读数 220

说真的气到我了,在家里说了一个小时小杰,因为这个模块默认叫说什么“小杰”,我人都裂开来这个小杰,在家里说了半个小时小杰,我妈问我怎么了最后解决问题了我来说一下
1.离咪头要远一点,这样说话识别率比较高(默认程序),说明文档说要靠着咪头说话,我个人怀疑靠着咪头说话会喷麦,所以就降低识别率了
2.语速可以稍微快一点别太慢,太慢识别率会低,别刻意的去说,我们正常说话的语速就可以了
3.一定要特别安静的时候而且不能有其他人说话,不然识别率基本为0
4.发音就和我们正常说话一样就行,不用特别刻意,不然识别不出来

语音识别入门

阅读数 2881

语音识别(二)

阅读数 26

没有更多推荐了,返回首页