智能机器人(17):自动应答

聊天机器人chat-robot,如果掐掉输入部分的语音识别,扣除输出部分的语音合成,剩下的就是机器应答,机器应答一般不算强人工智能,甚至连人工智能也算不上,不过应用场合不少。

语言应答这块,属于自然语言理解NLU的问题,加上机器翻译等,大的方向属于自然语言NLP处理范畴,很早就抛弃了语法分析方式,转为基于隐士马尔科夫的统计方法。隐士马尔科夫就是在你输入“美酒加”三个字之后就可以预测到接下来应该是“咖啡”,因为这个概率最高。具体的概率取决于训练所用的语料库,用人民日报体和网易盖楼体训练,概率肯定不一样。

分词对于中日韩等亚洲语言也是必须的,这些文字不像英文一样有空格可以分隔。中文分词开始是用字典法,适当控制颗粒的粗糙度也有满意效果,但是解决不了歧义问题,比如“他把球拍卖了”到底分成他把球拍/卖了还是他把球/拍卖了,所以后来也是转向基于统计的方法。

然后就是机器应答chatbot,比较成熟产品有开源的aliceBot和阿帕奇基金会的lucene,现在流行的有韩国的小黄鸡。

自己做着玩,可以有不同实现方式:

1、最简单粗暴的用数据库,写好keyword和description,然后select * from表where客户的关键词就可以了,不过没有模糊性,差错一个字就失配,知识库需要很大。

2、借助开源项目,比如中文分词用中科院的ICTCLAS,应答系统用aliceBot的AIML方式,或者阿帕奇lucene的搜索引擎方式。

搜索引擎检索方式,其实就是用全文检索系统,首先需要建立索引,常用的是倒排索引,这里倒排的意思就是矩阵转置,正排是关键词映射到页面,而倒排是页面映射到关键词,其实也就是页面的特征向量,对页面特征向量与搜索关键词计算余弦距离,就可以获得页面和检索的匹配程度。

例如一个页面的特征向量是[我,喜欢,爱玛仕],客户要搜索的特征向量是[我,喜欢,爱玛仕],两个向量的余弦为1,没什么可说的,这就是要寻找的目标。如果另一客户搜索的特征向量是是[他,喜欢,爱玛仕],那么虽然余弦不是1可是匹配程度也相当高,也可以作为全文检索结果给出。(不考虑甲醛、词频等等细节)

智能机器人(16):讯飞方案

科大讯飞的ASR和TSS口碑这么好,在PC和Android资源很多,虽然对*nix似乎支持不很到位,不过还是尝试一下,以下为测试内容。先说结果:如果说某度号称比google更懂中文会让人笑落满口牙,那么说科大讯飞更懂中文,应该当之无愧。讯飞主要提供:
1、语音合成
包括在线与离线合成,支持中文、英文、粤语、中英混、粤英混等。可以设定不同音色,包括普通话女童、普通话男声、普通话女声、粤语、东北话、河南话、湖南话、四川话等。支持多字符集,包括GB2312、GBK、Big5、Unicode、UTF-8等。
2、语音识别
提供在线与离线两种,功能包括前端预处理:端点检测、噪音消除、智能打断,后端识别:连续语音识别、个性化语音识别、置信度输出、多识别结果、多槽识别等。
3、语义理解
能处理基于文法规则的实际业务,支持用户通过自然语言向机器发出某种业务需求,如打电话、发短信、查天气、查股票、查航班、订酒店等。具备基于相似问句语义距离度量的智能知识问答。具备基于本体库自动构建及推理的智能问答。这块画蛇添足。

  • 一、流程

1、注册
1、到讯飞云去注册帐号,关联手机关联威信,建App,获ID,下载zip。
$ wget xunfei.tar.bz2
$ tar xvf xunfei.tar.bz2
2、头文件
在下载下来的include文件夹下,有五个文件:msp_errors.h、msp_types.h、msp_cmn.h、qisr.h、qtts.h,前两个是通用数据结构,qisr.h是语音识别头文件,qtts.h是语音合成头文件,在开发代码中include即可。
3、库文件
bin文件夹比较多,主要的是libmsc.so和libspeex.so两个库,复制到/usr/lib或/usr/bin目录即可。
$ sudo cp ./libmsc.so /usr/lib
4、make
$ cd samples/asr_sample
$ ./32bit_make.sh
5、可以测试
$ cd bin
$ ./asr_sample

  • 二、一般开发流程

1、建立项目目录
$ mkdir prj1
2、将SDK/Linux_SDK的src和bin和include和libs都拷贝到prj1目录下
$ cp …
3、在src下建源文件
$ cd src/
$ vi main.c
参考samples代码编辑自己源文件。
4、在prj1目录下创建Makefile文件:
DIR_INC = ./include
DIR_BIN = ./bin
DIR_LIB = ./libs

TARGET  = prj1
BIN_TARGET = $(DIR_BIN)/$(TARGET)

CROSS_COMPILE =
CFLAGS = -g -Wall -I$(DIR_INC)

ifdef LINUX64
LDFLAGS := -L$(DIR_LIB)/x64
else
LDFLAGS := -L$(DIR_LIB)/x86
endif

LDFLAGS += -lmsc -lrt -ldl -lpthread

OBJECTS := $(patsubst %.c,%.o,$(wildcard *.c))

$(BIN_TARGET) : $(OBJECTS)
$(CROSS_COMPILE)gcc $(CFLAGS) $^ -o $@ $(LDFLAGS)

%.o : %.c
$(CROSS_COMPILE)gcc -c $(CFLAGS) $< -o $@
clean:
@rm -f *.o $(BIN_TARGET)

.PHONY:clean

5、指定库位置
复制SDK/Linux_SDK/samples目录下“32bit_make.sh”或“64bit_make.sh”文件到prj1目录下。
修改libmsc.so库搜索路径
$ make clean;make
$ export LD_LIBRARY_PATH=$(pwd)/libs/x86/
6、source
$ cd prj1/
$ source 32bit_make.sh
7、run
$ cd bin/
$ ./main
8、日志文件位于bin/msc

  • 三、背景知识

1、wav
wav格式是目前Windows最直接保存声音数据的文件格式,在涉及声音信号处理时大多是对WAV文件直接操作。
2、riff
在Windows环境下大部分多媒体文件都依循着一种特定结构来存放信息,这称为资源互换文件格式(Resources Interchange File Format),称为RIFF,比如声音的WAV文件,视频的AVI文件,动画的MMM文件等。
RIFF是一种树状结构,基本组成单位是chunk(块),每个chunk由“辨识码-数据大小-数据”组成,所以一个chunk的长度就是“数据”的大小加8Byte。这是一般情况,因为通常chunk本身不会内部再包含chunk,除了极少的例外。RIFF相当于一个根目录,而格式辨识码则相当于具体的盘符如C:、D:。
3、文件头
扩展名为.wav的音频文件是一种非常简单的RIFF文件,其格式辨识码为”WAVE”,整个wav文件包括文件头和数据块两部分,文件头一般会有两种格式。
3.1、标准44字节文件头

3.1.1、RIFF WAVE Chunk:
以’RIFF’作为标示;然后紧跟着为size字段,该size是整个wav文件大小减去ID和Size所占用的字节数,即size:=FileLen-8;再然后是Type字段,为’WAVE’,表示是wav文件。结构定义如下:
struct RIFF_HEADER
{
char szRiffID[4];  // ‘R’,’I’,’F’,’F’
DWORD dwRiffSize;
char szRiffFormat[4]; // ‘W’,’A’,’V’,’E’
};Format Chunk
3.1.2、Format Chunk
以’fmt ‘作为标示。一般情况下Size为16,此时最后附加信息没有;如果为18则最后多了2个字节的附加信息。结构定义如下:
struct WAVE_FORMAT
{
WORD wFormatTag;
WORD wChannels;
DWORD dwSamplesPerSec;
DWORD dwAvgBytesPerSec;
WORD wBlockAlign;
WORD wBitsPerSample;
};
struct FMT_BLOCK
{
char  szFmtID[4]; // ‘f’,’m’,’t’,’ ‘
DWORD  dwFmtSize;
WAVE_FORMAT wavFormat;
};
3.2、58字节的文件头
这不是Windows的标准WAV文件,而是经过了一些软件处理的。
它比44字节的多了一个fact子块,储存了关于WAV文件内容的重要信息。用不到,暂时不看。
4、数据
data块装的是真正的声音数据,除非安装其它特殊软件否则Windows仅提供WAVE_FORMAT_PCM一种数据格式,即脉冲编码调制PCM:Pulse Code Modulation,其数据存放形式如下图所示,根据声道数不同及取样位数的不同,安排4位的位置。

Data Chunk头结构定义如下:
struct DATA_BLOCK
{
char szDataID[4]; // ‘d’,’a’,’t’,’a’
DWORD dwDataSize;
};
Windows将16位值取值范围定为[-32768,32767],所以0并不一定代表无声,要注意声音格式是l6位还是8位。解压缩后得到的文件仅仅是裸数据,如果不能正常播放声音,可以按照标准的44字节格式,在解码数据前编写一个正确的文件头,使其成为一个有效文件。
5、例如一个真正的wave文件

6、继续说明
Wav全称是Wave,说明就是将音频文件的波形完整记录,要记录波形需要两个最基本参数:
6.1、采样率,以怎样的频率记录波形的变化,常见的WAVE主要有两种,分别对应于单声道的11.025KHz采样率和8Bit采样深度以及双声道的44.1KHz采样率和16Bit的采样值深度。单声道音频文件采样数据为八位的短整数(short int 00H-FFH),双声道立体声声音文件采样数据为16位的整数(int),高八位和低八位分别代表左右两个声道。所有CD一律采用44.1KHz,而DVD/BD视频音轨一律采用48KHz,原则上更高的采样率更为精准,但是一般认为44.1KHz就接近人耳极限。
6.2、采样深度,用多少字节的储存量来储存音频波形,一般采用的是16bit,及更高的24bit,再高的深度意义不大。这样就不难回答为什么常见WAV文件比特率是1141KBit/s了,44.1KHz * 32bit =1141.2。
6.3、还要注意不同采样频率最好整倍数切换。例如下图曲线一是原始采样音频,一共四段五点;如果像曲线二采样率增加一倍,即八段九点,基本无差异;如果采样率为1.5倍,即波形三的6段7点,则新采样波形四就不可接受了。

6.4、音频压缩
音频编码压缩分为有损无损两种,前者例如MP3波形发生了改变,后者例如FLAC其波形和源文件毫无差异。有损效率高,MP3常见比特率在200KBit/s只是WAV的1/6。

  • 五、讯飞的语音合成

按照riff格式讯飞定义的文件头结构:
typedef struct _wave_pcm_hdr
{
char            riff[4];                // = “RIFF”
int  size_8;                 // = FileSize – 8
char            wave[4];                // = “WAVE”

char            fmt[4];                 // = “fmt ”
int  fmt_size;  // = 下一个结构体的大小:16 | 18
short int       format_tag;             // = PCM : 1
short int       channels;               // = 通道数 : 1
int  samples_per_sec;        // = 采样率 : 8000 | 6000 | 11025 | 16000
int  avg_bytes_per_sec;      // = 每秒字节数 : samples_per_sec * bits_per_sample / 8
short int       block_align;            // = 每采样点字节数 : wBitsPerSample / 8
short int       bits_per_sample;        // = 量化比特数: 8 | 16

char            data[4];                // = “data”;
int  data_size;              // = 纯数据长度 : FileSize – 44
} wave_pcm_hdr;
默认文件头是这样:
wave_pcm_hdr default_wav_hdr =
{
{ ‘R’, ‘I’, ‘F’, ‘F’ },
0,
{‘W’, ‘A’, ‘V’, ‘E’},
{‘f’, ‘m’, ‘t’, ‘ ‘},
16,
1,
1,
16000,
32000,
2,
16,
{‘d’, ‘a’, ‘t’, ‘a’},
0
};
音频合成主要代码:
int text_to_speech(const char* src_text, const char* des_path, const char* params)
{
int          ret          = -1;
FILE*        fp           = NULL;
const char*  sessionID    = NULL;
unsigned int audio_len    = 0;
wave_pcm_hdr wav_hdr      = default_wav_hdr;   //默认文件头
int          synth_status = MSP_TTS_FLAG_STILL_HAVE_DATA; //状态机模型

if (NULL == src_text || NULL == des_path) …
fp = fopen(des_path, “wb”); …

//一、pre-合成
sessionID = QTTSSessionBegin(params, &ret); //(1)获得本次sessionID
if (MSP_SUCCESS != ret) …
ret = QTTSTextPut(sessionID, src_text, (unsigned int)strlen(src_text), NULL); //(2)put代合成的文本
if (MSP_SUCCESS != ret) …

//二、合成
fwrite(&wav_hdr, sizeof(wav_hdr) ,1, fp); //(3)添加文件头header
while (1)
{
//获取合成音频
const void* data = QTTSAudioGet(sessionID, &audio_len, &synth_status, &ret);
if (MSP_SUCCESS != ret) …
if (NULL != data)
{
fwrite(data, audio_len, 1, fp); //(4.1)添加音频数据
wav_hdr.data_size += audio_len; //(4.2)刷新大小
}
if (MSP_TTS_FLAG_DATA_END == synth_status) break; //出口
usleep(150*1000); //防止频繁占用CPU
}
if (MSP_SUCCESS != ret) …
//修正wav文件头
wav_hdr.size_8 += wav_hdr.data_size + (sizeof(wav_hdr) – 8); //刷新大小

//将修正过的数据写回文件头部,音频文件为wav格式
fseek(fp, 4, 0);
fwrite(&wav_hdr.size_8,sizeof(wav_hdr.size_8), 1, fp); //写入size_8的值
fseek(fp, 40, 0); //将文件指针偏移到存储data_size值的位置
fwrite(&wav_hdr.data_size,sizeof(wav_hdr.data_size), 1, fp); //写入data_size的值
fclose(fp);
fp = NULL;

//三、post-合成
ret = QTTSSessionEnd(sessionID, “Normal”);
if (MSP_SUCCESS != ret) …
return ret;
}
主程序:《iFlytek MSC Reference Manual》
int main(int argc, char* argv[])
{
int         ret                  = MSP_SUCCESS;
const char* login_params         = “appid = 5786f5??, work_dir = .”; //登录参数,appid与msc库绑定,勿随意改动
/*
* voice_name:    合成发音人,0:数值优先,1:完全数值,2:完全字符串,3:字符串优先。
* sample_rate:   合成音频采样率
* speed:         合成音频对应的语速
* volume:        合成音频的音量
* pitch:         合成音频的音调
* rdn:           合成音频数字发音方式
* text_encoding: 合成文本编码格式
*/
const char* session_begin_params = “voice_name = xiaoyan, text_encoding = UTF8, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn

= 2”;
const char* filename             = “tts_sample.wav”; //合成的语音文件名称
const char* text                 = “语音合成示例,”; //合成文本

//一、登录
ret = MSPLogin(NULL, NULL, login_params);//第一个参数是用户名,第二个参数是密码,第三个参数是登录参数
if (MSP_SUCCESS != ret) …
//二、合成
ret = text_to_speech(text, filename, session_begin_params);
if (MSP_SUCCESS != ret) …
//三、退出
MSPLogout();
return 0;
}
主要是倒腾这几个函数:
const char *MSPAPI  QTTSSessionBegin (const char *params, int *errorCode)
int MSPAPI  QTTSTextPut (const char *sessionID, const char *textString, unsigned int textLen, const char *params)
const void *MSPAPI  QTTSAudioGet (const char *sessionID, unsigned int *audioLen, int *synthStatus, int *errorCode)
int MSPAPI  QTTSGetParam (const char *sessionID, const char *paramName, char *paramValue, unsigned int *valueLen)
int MSPAPI  QTTSSessionEnd (const char *sessionID, const char *hints)
主要参数是下面这些:
voice_name,发音人。如男声、女声、童声等。参考《发音人》列表。
speed,合成音频语速。0-100之间的整数,数值越大语速越快。默认为50
volume,合成音频音量。0-100之间的整数,数值越大音量越大。默认为50
pitch,合成音频音调。0-100之间的整数,数值越大音调越高。默认为50
text_encoding,合成文本编码。GB2312;GBK;BIG5;UNICODE;GB18030;UTF8
background_sound,成音频中的背景音。0:无背景音乐 1:有背景音乐。默认为0
aue,音频编码格式和压缩等级。编码算法:raw;speex;speex-wb;编码等级:raw:无等级。speex系列:0-10;默认为speex-wb;7。speex对应sample_rate=8000
speex-wb对应sample_rate=16000。
sample_rate,合成音频格式。8000 16000,默认为16000
ttp,合成文本类型。text: 普通格式文本;ssml:ssml格式文本。默认为text
rdn,合成音频数字发音。0:数值优先,1:完全数值,2:完全字符串,3:字符串优先。默认为0
《发音人》列表:
xiaoyan  普通话  青年女声;yufeng  普通话  青年男声;唐老鸭  donaldduck  普通话  卡通;许小宝  baybyxu  普通话  童声;楠楠  nannan  普通话  童声;
晓倩  xiaoqian  东北话  青年女声;晓蓉  xiaorong  四川话  青年女声;小强  xiaoqiang  湖南话  青年男声;晓美  xiaomei  粤语  青年女声;等。

  • 六、讯飞的语音听写

要么上传语法文件,要么上传用户词表:
int upload_userwords()
{
char*  userwords = NULL;
unsigned int len  = 0;
unsigned int read_len = 0;
FILE*  fp  = NULL;
int  ret  = -1;

fp = fopen(“userwords.txt”, “rb”); …
fseek(fp, 0, SEEK_END);
len = ftell(fp); //获取音频文件大小
fseek(fp, 0, SEEK_SET);

userwords = (char*)malloc(len + 1);
if (NULL == userwords) …

read_len = fread((void*)userwords, 1, len, fp); //读取用户词表内容
if (read_len != len) …
userwords[len] = ‘�’;

MSPUploadData(“userwords”, userwords, len, “sub = uup, dtt = userword”, &ret); //上传用户词表
if (MSP_SUCCESS != ret) …

return ret;
}
核心的听写代码
void run_iat(const char* audio_file, const char* session_begin_params)
{
const char*  session_id   = NULL;
char   rec_result[BUFFER_SIZE]  = {NULL};
char   hints[HINTS_SIZE]  = {NULL}; //hints为结束本次会话的原因描述,由用户自定义
unsigned int  total_len   = 0;
int   aud_stat   = MSP_AUDIO_SAMPLE_CONTINUE ; //音频状态
int   ep_stat    = MSP_EP_LOOKING_FOR_SPEECH; //端点检测
int   rec_stat   = MSP_REC_STATUS_SUCCESS ; //识别状态
int   errcode    = MSP_SUCCESS ;

FILE*   f_pcm    = NULL;
char*   p_pcm    = NULL;
long   pcm_count   = 0;
long   pcm_size   = 0;
long   read_size   = 0;
if (NULL == audio_file) …

f_pcm = fopen(audio_file, “rb”);
if (NULL == f_pcm) …

fseek(f_pcm, 0, SEEK_END);
pcm_size = ftell(f_pcm); //获取音频文件大小
fseek(f_pcm, 0, SEEK_SET);

p_pcm = (char *)malloc(pcm_size);
if (NULL == p_pcm) …

read_size = fread((void *)p_pcm, 1, pcm_size, f_pcm); //读取音频文件内容
if (read_size != pcm_size) …

printf(“n开始语音听写 …n”);
session_id = QISRSessionBegin(NULL, session_begin_params, &errcode); //听写不需要语法,第一个参数为NULL
if (MSP_SUCCESS != errcode) …

while (1)
{
unsigned int len = 10 * FRAME_LEN; //每次写入10帧*20ms=200ms音频。16k采样率,16位音频,每帧音频20ms、大小640Byte
int ret = 0;

if (pcm_size < 2 * len) len = pcm_size;
if (len <= 0)  break; //出口,识别尾部

aud_stat = MSP_AUDIO_SAMPLE_CONTINUE;
if (0 == pcm_count) aud_stat = MSP_AUDIO_SAMPLE_FIRST;

printf(“>”);
ret = QISRAudioWrite(session_id, (const void *)&p_pcm[pcm_count], len, aud_stat, &ep_stat, &rec_stat);
if (MSP_SUCCESS != ret) …

pcm_count += (long)len;
pcm_size  -= (long)len;

if (MSP_REC_STATUS_SUCCESS == rec_stat) //已经有部分听写结果
{
const char *rslt = QISRGetResult(session_id, &rec_stat, 0, &errcode);
if (MSP_SUCCESS != errcode) …
if (NULL != rslt)
{
unsigned int rslt_len = strlen(rslt);
total_len += rslt_len;
if (total_len >= BUFFER_SIZE) …
strncat(rec_result, rslt, rslt_len);
}
}

if (MSP_EP_AFTER_SPEECH == ep_stat) break;//出口,到达静音
usleep(200*1000); //模拟人说话时间间隙。200ms对应10帧的音频
}
errcode = QISRAudioWrite(session_id, NULL, 0, MSP_AUDIO_SAMPLE_LAST, &ep_stat, &rec_stat);
if (MSP_SUCCESS != errcode) …

while (MSP_REC_STATUS_COMPLETE != rec_stat)
{
const char *rslt = QISRGetResult(session_id, &rec_stat, 0, &errcode);
if (MSP_SUCCESS != errcode) …
if (NULL != rslt)
{
unsigned int rslt_len = strlen(rslt);
total_len += rslt_len;
if (total_len >= BUFFER_SIZE) …
strncat(rec_result, rslt, rslt_len);
}
usleep(150*1000); //防止频繁占用CPU
}
printf(“n语音听写结束n”);
printf(“%sn”,rec_result);
printf(“=============================================================n”);

QISRSessionEnd(session_id, hints);
}
主程序:
int main(int argc, char* argv[])
{
int   ret  = MSP_SUCCESS;
int   upload_on = 1; //是否上传用户词表
const char*   login_params = “appid = 5786f5??, work_dir = .”; // 登录参数,appid与msc库绑定勿改

const char* session_begin_params = “sub = iat, domain = iat, language = zh_ch, accent = mandarin, sample_rate = 16000,

result_type = plain, result_encoding = utf8”;

/* 用户登录 */
ret = MSPLogin(NULL, NULL, login_params); //第一个用户名,第二个密码,第三个登录参数
if (MSP_SUCCESS != ret) …

printf(“演示示例选择:是否上传用户词表?n0:不使用n1:使用n”);
scanf(“%d”, &upload_on);
if (upload_on)
ret = upload_userwords();

run_iat(“wav/iflytek02.wav”, session_begin_params);
exit:
MSPLogout(); //退出登录
return 0;
}

  • 七、录音

为了测试,需要录音,用Sox。Sox是Lance Norskog创立的最著名的声音文件格式转换工具,跨平台,支持常见格式,能够进行声音滤波、采样频率转换等。Sox附带有rec,play两个程序,rec是用来录音的,play是用来播放的。
Sox的语法格式如下所示:
sox  全局参数  格式化参数  输入文件1  格式化参数  输入文件2 … 格式化参数   输出文件 效果器全局参数在最前面。每个输入文件都有相应的格式化参数,可以有多个输入文件,在每一个输出文件前面再加上格式化参数,最后是效果器。
1、一个简单的命令:
$ sox file1.wav -v 0.6 file2.wav
-v是调整音量的选项,是一种线性调整,0.6并不是调整到原先的0.6,而是幅值调整,如果-v后面的数字比1大,则增加音量,反之则减少音量,如果是负数那么在调整的同时还对音频进行反相变换,但也不是可以任意增加的,取值太大容易产生削波现象。
2、要取什么值好呢:
$ sox file1.wav -n stat -v
$ 1.003
这就是不失真最大调整量了。
作用是对音频文件做一个统计分析,并将结果打印到标准错误文件。参数方面,-n表示输出文件为空。stat为效果器,-v表示将要打印跟音量调整有关内容。
3、查看文件信息
$ sox 01.wav -n stat
4、提取
提取开头的10秒
$ sox 01.wav 011.wav trim 0 10
提取10-277秒的音频
$ sox 01.wav 012.wav trim 10 227
5、调整
调整采样率为48000:
$ sox file1.wav -r 48000 file2.wav
6、转换
wav转mp3
$ sox 01.wav sox 01.mp3
7、单声道转立体声:
$ sox file1.wav -c 2 file2.wav
其中-c就是声道转换选项,-c 2可写成-c2,所以-c1表示单声道,-c4表示4声道。
8、组合
打印细节,音量调整,采样率调整,声道转换,等等都结合起来:
$ sox -V4 -v 1.2   file1.wav -r 48000 -c 2 file2.wav
其中-V4表示打印最多细节。
9、效果器
样本用的是一小段自录声音(3.15分钟长,’wav’格式,44.1 kHz采样速率,16bit单声道)。
10、混合
$ play 01.wav mixer 0.3,0.5,0.8,0.6
采用了mixer效果器,它通过混合或者减少音轨从而减少音轨数,或者通过复制音轨而增加音轨数。
11、节拍器
$ play 01.wav tempo -q 0.8 82 20  16
下面例子则应用了tempo(节拍)效果器:
0.8设置新节拍相对于老节拍的比率,82设置所选算法要划分音频的片段大小,单位毫秒,20是音频长度,依靠它来搜索以寻找重叠点,16是重叠长度。
12颤动器
$ play 01.wav tremolo 3.5 60
3.5是颤音频率,,单位是赫兹Hz,60是深度百分比,具体来说就是”颤”到多长或深。
13、淡入淡出
$ play 01.wav fade t 00:00:100.09
上面例子中,fade是效果器名字,t是声波包络线形式,t是线性斜坡,选q则意味着是正弦波的四分之一,h表示正弦波一半,l为对数,p为倒置抛物线。默认是线性斜坡。00:00:100.09是以hh:mm:ss.fraq形式表示的时间,也可用采样数来算,如设为8000s则为8000个样本。
$ play 01.wav fade t 00:00:50.09 00:01:00 00:00:06
上面是淡入效果,那么要设置淡出效果。上例中t上面已讲,00:00:50.09是从0开始算起,到淡入结束所花费的时间;00:01:00是开始淡出的时间点,00:00:06是开始淡出到结束所花费的时间。也就是说,从00:01:00开始淡出,花费6秒即00:00:06的时间就结束了。上面的时间都可以选择以样本数量为单位,如上所述。
14、回响
自然界中,回声处处可见,比如站在高山上,向周围的山喊话,就会引起回声,在喊和回声之间的时间间隔就是延迟,它的响度就是衰减值,下面给出一个回响例子:
$ play file.xxx echo 0.8 0.88 60 0.4
上式听起来就象用两个乐器演奏同一个样本一样,0.8是输入音量,0.88是输出音量,60是延迟,单位是毫秒,0.4是相对于输入音量的衰减值。
如果延迟时间变长,听起来更象在山顶上的露天演唱会:
$ play file.wav echo 0.8 0.88 1000 0.4
衰减值最好不要大于0.5,否则可能引起输出饱和。
假如延迟很短,听起来象(金属的)机器人的表演。
$ play file.wav 0.8 0.88 6 0.4
想要更多回响也可以实现:
$ play file.wav echo 0.8 0.9 1000 0.3 1800 0.25
如果是站在群山之间,还可能会引起连续回响,即回响本身有碰到邻近山峰,反弹回来,又弹回去,这种效果就是回声,它是连续回响的意思,如果是单独应用一次回声,效果和回响是一样的,下面看一个两次回声例子:
$ play file.wav echos 0.8 0.7 700 0.25 700 0.3
在上式中,echos就是回声效果器,应用这个效果器,回响将被弹回来两次,因为两次延迟时间相同,都是700,这种回响叫对称回声,来一个不对称的回声:
$ play file.xxx echos 0.8 0.7 700 0.25 900 0.3
下面这个例子听起来就象在汽车里演奏一样:
$ play file.wav echos 0.8 0.7 40 0.25 63 0.3
上式由于延迟时间短,听起来感觉有点沉闷,不是吗?
15、rec
Sox附带的程序有rec,play两个程序,rec是用来录音的,play是用来试听效果的,它们语法跟sox是类似的,只是rec时候输入源就变成了内部或外部的设备。常规的,一般录wav用sox就ok,录制mp3可选用mpegrec。
最简单的指定文件名即可录音:
$ rec file.wav
带参数录音:
$ rec -r 16000 -b 16  -c 1  666.wav
以上符合讯飞要求:采样率16K或8KHz,采样位是16位,单声道,格式PCM或WAV。
主要参数:
-r 16000, -r指定采样速率,这里为16K
-b 16,-s指定采样位数,默认-s b为8位,这里-s w为16位。
-c 1,-c指定通道数, 这里-c 1为单通道
-v 12,-v指定音量。
-t mp3,-t指定文件类型,默认wav,这里为mp3

  • 八、综合测试

0、设置环境:
$ export PATH=~/XF_U1404401/Linux_voice_1.109/bin:$PATH
1、录制音频:
$ rec -r 16000 -b 16  -c 1  wav/dehaoSpeech.wav
2、识别称文本:
$ iat_sample Y
3、合成另外一种语音:
$ tts_sample  –voice_name=xiaomei   “我爱北京天安门”  dehaoSpeech.wav
4、播放这段语音:
$ play dehaoSpeech.wav
5、还是写个脚本吧:
#!/bin/sh
export PATH=~/XF_U1404401/Linux_voice_1.109/bin:$PATH
rm wav/dehaoSpeech.wav
rec -r 16000 -b 16  -c 1  wav/dehaoSpeech.wav
tts_sample  –voice_name=xiaomei   `iat_sample Y`  dehaoSpeech.wav
play dehaoSpeech.wav
说明:
1、脚本流程就是上面的手工流程一录、二识、三合、四播:(1)rec录制一段我的语音–>(2)文本识别iat_sample识别出这段语音成文字–>(3)语音合成程序tts_sample把这段文字合成某种方言–>(4)play播放这段方言。
2、对语音合成程序tts_sample添加了一些参数处理:

3、用了参数的最长的这句,“tts_sample”是语音合成 这个程序名,“–voice_name=xiaomei ”是第一个参数说明使用xiaomei这个粤语女声,两边用反颚符号“包围起来的`iat_sample Y`表示这个识别程序的文本结果将作为合成程序tts_sample的第二个参数,“dehaoSpeech.wav”作为第三个参数,指定了位置。

智能机器人(15):语音合成

语音合成,术语指文本到声音TTS:text to speech,习惯T2S:text2speech,类似coder4context。
TTS大体包括:
1、文本分析,解析数字/缩写等。
2、语音分析,分解为语素单元。
3、韵律分析,例如重音/加重等更真实华。
4、音节分析。
常用的语音合成有eSpeak,Festival等,前者是用于英语语系,后者支持多语言但重点应用在Linux。

  • 1、Linux应用

1、安装包
$ sudo apt-get install festival
这个有可能需要的
$ sudo apt-get install libasound2
2、交互模式测试
$ festival
festival> (SayText “ni hao,wo lai zi zhe jiang”)
festival>
3、命令行模式测试
读字符
$ echo “hello,wo lai zi zhe jiang” | festival –tts
读日期
$ date ‘+%A, %B %e, %Y’ | festival –tts
读文件
$ echo “hello,wo lai zi zhe jiang” > ./sampletts
$ festival –tts sampletts #直接读myfile里的内容
写一个PHP脚本,读日期,测试下
$ nano today.php
#!/usr/bin/php -q
<?php
srand( (double)microtime()*1000000 );
echo “Today number is ” . rand(1,25);
?>
$ today.php | festival –tts
4、安装一个测试的Python脚本
$ wget https://storage.googleapis.com/google-code-archive-source/v2/code.google.com/pyfestival/source-archive.zip
//$ svn checkout http://pyfestival.googlecode.com/svn/trunk/pyfestival-read-only
解压缩之后,安装
$ sudo python setup.py install
5、测试脚本
$ python
>>>import festival
>>>festival.say(“Good night.”)
6、音频存储
$ echo “Hello, good day” | text2wave -scale 50 -o hello.wav
text2wave读取文本文件内容转换为音频语音,-scale调节音量,-o保存到ulaw/snd/aiff/riff/nist/wav音频文件。

  • 2、ROS应用

1、安装需要的sound_play包
$ sudo apt-get install ros-indigo-sound-play
这个有可能需要的
$ sudo apt-get install ros-indigo-audio-common
$ sudo apt-get install libasound2
2、建立包含交互node的一个简单package,该包里面python编写的client节点把需要朗读的文本通过/robotsound主题发送到server节点。
$ cd ~/catkin_ws/src
$ catkin_create_pkg sample_tts rospy roscpp sound_play std_msgs
$ cd sample_tts
$ mkdir scripts
3、建立node的Python脚本
$ nano scripts/test.py
#!/usr/bin/env python
import roslib; roslib.load_manifest(‘sample_tts’)
import rospy, os, sys
from sound_play.msg import SoundRequest
from sound_play.libsoundplay import SoundClient
if __name__ == ‘__main__’:
rospy.init_node(‘soundplay_test’, anonymous = True)
soundhandle = SoundClient()
rospy.sleep( 1)
soundhandle.stopAll()
print ‘Starting TTS’
soundhandle.say(‘Hello world!’)
rospy.sleep( 3)
s = soundhandle.voiceSound(“Hello World, you are welcome”)
s.play()
rospy.sleep( 3)
4、测试,先运行服务器
$ roslaunch sound_play soundplay_node.launch
5、测试,运行测试脚本
$ rosrun sample_tts test.py

  • 3、切换语音包

1、默认声音
$ rosrun sound_play soundplay_node.py
$ rosrun sound_play say.py “Hello there, Good night.”
注意空格,注意,要比.停顿时间要短。 然后默认是一个帅小伙的声音响起来…
2、需要添加其他语音文件。
为安装语音文件,先查看安装的语音:
$ sudo apt-cache search –names-only festvox-*
再额外安装一个语音:
$ sudo apt-get install festvox-don
再试听:
$ rosrun sound_play say.py “Hello there, Good night.”
一个含混的声音…
3、回环测试
$ roslaunch rbx1_speech talkback.launch
这就是鹦鹉学舌,语音输入被转化成默认语音输出。

智能机器人(13):语音识别

  • 1、语音处理

语音处理包括两部分:(1) 一块是语音识别SR:Speech Recognition,也称为自动语音识别ASR:Automatic Speech Recognition;(2) 另一块是语音合成SS:Speech Synthesis,也称为TTS:Text-To-Speech。
语音处理目前多为基于语音识别芯片的嵌入实现,也有靠软件实现的例如商用的IBM的Viavoice和MS的SAPI以及开源的Sphinx和Julius等,都是些面向非特定人的大词汇量的连续语音识别系统。

  • 2、语音识别

语音识别,属于模式识别的一种应用,将未知的输入语音的模式和已知语音库里的参考模式逐一比较,所获得的最佳匹配的参考模式即为识别出来的结果。
语音识别目前大多是基于统计模式的,主流算法有基于参数模型的隐式马尔可夫模型HMM方法、基于人工神经网络ANN和支持向量机SVN的识别方法等。

  • 3、识别模型

(1)根据语音的机理,语音识别大框架可以分为语音层和语言层两个层级,可以理解为语音层 即子音母音或者叫声母韵母,而语言层则是sequence of words。(2) 根据功能,连续语音识别系统,主要分为特征提取,声学模型训练,语言模型训练、解码器和搜索算法四大块。

更琐碎的分为:
1、预处理。滤除次要信息和背景噪声,对语音信号作端点检测从而找出语音始末位置,假设在10-30ms内语音是平稳的从而将语音分帧。
2、特征提取。背景过滤,保留能够反映语音本质特征的信息,取出反映语音信号特征的关键参数形成特征向量序列,获得特征向量后由此特征向量通过计算余弦值可以初步获得被选的单词文本。
特征提取方法都是频谱衍生的,sphinx是用Mel频率倒谱系数MFCC。首先用FFT将时域信号转化成频域,之后对它的对数能量谱依照Mel刻度分布的三角滤波器组进行卷积,最后对各滤波器输出所构成的向量进行离散余弦变换DCT,取其前N个系数。sphinx用大概10ms的帧frames去分割语音波形,然后对每帧提取可以代表该帧语音的39个数字,这39个数字就是该帧语音的MFCC特征,即特征向量。
3、字典,用于选练声学模型。
4a、声学模型,通常是隐式马尔科夫模型,从而由声音特征可以获得音素单元。
4b、声学模型训练,由训练语音库的特征参数训练出声学模型参数。语音识别时将待识别的语音的特征参数同声学模型进行匹配得到识别结果。目前语音识别系统多用隐式马尔可夫模型HMM进行声学模型建模。HMM模型的建模单元,可以是音素,音节,词等各个层次。对于小词汇量的语音识别系统,可以用音节进行建模。对于词汇量大的识别系统,一般选取音素即声母/韵母进行建模。识别规模越大识别单元选取的越小。HMM是对语音信号的时间序列结构建立统计模型,将其看作一个数学上的双重随机过程:一个是用具有有限状态数的Markov链来模拟语音信号统计特性变化的隐含(马尔可夫模型的内部状态外界不可见)的随机过程,另一个是与Markov链的每一个状态相关联的外界可见的观测序列(通常就是从各个帧计算而得的声学特征)的随机过程语音识别中使用HMM,通常是用从左向右单向、带自环、带跨越的拓扑结构来对识别基元建模,一个音素就是一个三至五种状态的HMM,一个词就是构成词的多个音素的HMM串行起来构成的HMM,而连续语音识别的整个模型就是词和静音组合起来的HMM。

5a、语言模型,训练文本序列,除了包括前述字典,还有额外材料。
5b、语言模型训练,语言模型是用来计算一个句子出现概率的概率模型。它主要用于决定哪个词序列的可能性更大,或者在出现了几个词的情况下预测下一个即将出现的词语的内容。换个说法即语言模型是用来约束单词搜索的。语言模型分为字典知识、语法知识、句法知识三个层次,Sphinx中是采用二元语法和三元语法的统计语言概率模型,也就是通过前一个或两个单词来判定当前单词出现的概率P(w2| w1),P(w3| w2, w1)。
6、解码和搜索算法,通过语言模型和字典,给出概率可能的结果。
解码即指语音技术中的识别过程。根据己经训练好的HMM声学模型、语言模型及字典建立一个识别网络,根据搜索算法在该网络中寻找最佳的一条路径,这个路径就是能够以最大概率输出该语音信号的词串。所以解码操作即指搜索算法:是指在解码端通过搜索技术寻找最优词串的方法。为在搜索中利用各种知识源,通常要进行多遍搜索,第一遍使用代价低的知识源(如声学模型、语言模型和音标词典),产生一个候选列表或词候选网格,在此基础上进行使用代价高的知识源(如4阶或5阶的N-Gram、4阶或更高的上下文相关模型)的第二遍搜索得到最佳路径。

4、sphinx

Sphinx产生于卡内基梅隆大学CMU,最早由李开复Kai-Fu Lee开发于1987年,是一个大词汇非特定人连续语音识别系统。pocketSphinx是Sphinx的桌面版,词汇量中等计算量较小。
组成包括以下:
1、Sphinxbase — Pocketsphinx所需要的支持库,主要完成的是语音信号的特征提取;
2、Pocketsphinx —用C语言编写的轻量级识别库,主要是进行识别的。
3、Sphinx3 — 为语音识别研究用C语言编写的解码器
3、Sphinxtrain —声学模型训练工具
4、CMUclmtk —语言模型训练工具

  • 5、Linux应用

1、安装需要的pocketsphinx包
$ sudo apt-get install pocketsphinx-hmm-wsj1 #install HMM of Pocket Sphinx
$ sudo apt-get install pocketsphinx-lm-wsj #install LM of Pocket Sphinx
$ sudo apt-get install python-pocketsphinx #install the Python extension of Pocket Sphinx
2、验证能够跑得起来
$ pocketsphinx_continuous
READY….
出现ready安装成功
3、文件说明
(1)安装后,模型位于/usr/share/pocketsphinx/model文件夹,里面hmm表示隐马尔可夫声学模型,lm表示language model语言模型。
(2)语言模型,lm/en_US文件夹,包括cmu07a.dic和hub4.5000.DMP。
(3)声学模型,hmm/en_US/hub4wsj_sc_8k文件夹,包括:feat.params/mdef/means/noisedict/sendump/transition_matrices/variances
4、再用默认的模型测试下
$ pocketsphinx_continuous -hmm /usr/share/pocketsphinx/model/hmm/en_US/hub4wsj_sc_8k -lm /usr/share/pocketsphinx/model/lm/en_US/hub4.5000.DMP -dict/usr/share/pocketsphinx/model/lm/en_UScmu07a.dic
$ pocketsphinx_continuous -lm  ~/catkin_ws/src/rbx1/rbx1_speech/config/nav_commands.lm  -dict ~/catkin_ws/src/rbx1/rbx1_speech/config/nav_commands.dic

5、怎样建立英文的语言模型
(1)建立语料库,vi corpus.txt
(2)利用在线工具LMTool建立语言模型,http://www.speech.cs.cmu.edu/tools/lmtool.html,COMPILE KNOWLEDGE BASE。
(3)把得到的文件解压,即可得到.dic和.lm文件。
$ tar xzf ***.tar.gz
测试:
$ pocketsphinx_continuous -hmm /usr/share/pocketsphinx/model/hmm/en_US/hub4wsj_sc_8k -lm /usr/share/pocketsphinx/model/lm/en_US/hub4.5000.DMP -dict /usr/share/pocketsphinx/model/lm/en_UScmu07a.dic
英文的识别,尚好,还可以。

6、如何建立中文普通话的语言模型
官网上:声学模型,是zh_broadcastnews_16k_ptm256_8000.tar.bz2;语言模型,是zh_broadcastnews_64000_utf8.DMP;字典文件,是zh_broadcastnews_utf8.dic。
如果自安装:pocketsphinx-0.7/model/hmm/zh/tdt_sc_8k目录下是中文声学模型,pocketsphinx-0.7/model/lm/zh_CN目录下是中文语言模型,
(1)下载中文普通话语言模型MandarinLanguageModel:zh_broadcastnews_utf8.dic和zh_broadcastnews_64000_utf8.DMP。
(2)下载中文普通话新闻播音声学模型MandarinBroadcastNewsAcousticModels:zh_broadcastnews_16k_ptm256_8000文件夹
(3)解压缩
$ tar xjf zh_broadcastnews_16k_ptm256_8000.tar.bz2
(4)得到的声学模型包括以下:feat.params/mdef/means/noisedict/sendump/transition_matrices/mixture_weights/variances
(3)测试,
$ pocketsphinx_continuous -hmm ~/zdhSpeech2/zh_broadcastnews_ptm256_8000 -lm ~/zdhSpeech2/zh_broadcastnews_64000_utf8.DMP -dict ~/zdhSpeech2/zh_broadcastnews_utf8.dic
中文的是被效果,不咋的,估计还是得训练模型。

7、语言模型的训练
(0)准备语料库,产生词汇表,每个utterances由 <s> 和 </s>分隔,结尾不留“n”。
#vi weather.txt
(1)命令text2wfreq:统计文本文件中每个词出现的次数,得到后缀为wfreq的文件。命令wfreq2vocab:统计文本文件中含有多少个词,即有哪些词。
# text2wfreq < weather.txt | wfreq2vocab > weather.tmp.vocab
(2)text2idngram:列举文本中出现的每一个n元语法。产生一个二进制文件,含有一个n元数组的数值排序列表,对应于与词有关的的N-Gram。
# text2idngram -vocab weather.vocab  -idngram weather.idngram < weather.closed.txt
(3)idngram2lm:输入文件包括一个idngram文件,一个vocab文件和一个ccs文件,输出是一个后缀为binlm的语言模型文件。其中ccs文件指句首和句尾的静音<s>和</s>
#idngram2lm -vocab_type 0 -idngram weather.idngram -vocab weather.vocab -arpa weather.arpa
(4)命令binlm2arpa:是将binlm文件转换为实验中需要的arpa格式语言模型文件。
(5)#sphinx_lm_convert -i weather.arpa -o weather.lm.DMP
如果语言模型比较大,最好就转换为CMU的二进制格式 (DMP),这样可以加快加载语言模型的速度,减少解码器初始化的时间。但小模型来说就这个必要,因为sphinx3能处理这两种后缀名的语言模型文件。
(6)这样最终生成了语言模型weather.lm.DMP,此文件为解码器端所需要的文件格式
8、声音模型的改进
(1)创建语料库,共需要四个文件:
arctic20.txt,文本文件:里面是中文的句子
arctic20.fileids,控制文件:记录语音文件(读arctic20.txt里面的句子的录音)的路径
arctic20.transcription,脚本文件:中文句子和语音文件的对应关系
arctic20.dic,字典文件:记录arctic20.txt里面的句子因素的音标组成
(2)声音录制:
$ sudo apt-get install sox
$ vi rec_wav.sh
$ for i in `seq 1 12`; do
fn=`printf arctic_%04d $i`;
read sent; echo $sent;
rec -r 16000 -e signed-integer -b 16 -c 1 $fn.wav 2>/dev/null;
done < arctic20.txt
$ chmod 777 rec_wav.sh
这个脚本会显示一句话然后进入录音,把这个句子读出来然后按ctrl+c显示下一句话然后录音,如此循环。
测试下,逐个播放:
for i in *.wav; do play $i; done
(3)适应声学模型
首先拷贝默认的pocketsphinx自带的中文声学模型到当前目录下
$ cp -a /usr/local/share/pocketsphinx/model/hmm/zh/tdt_sc_8k/ .
对录制的wav语音文件提取MFCC特征,而且须用和默认的模型相同的声学模型参数去提取这些特征,他们存储在声学模型目录的feat.params文件中。
$ sphinx_fe -argfile tdt_sc_8k/feat.params -samprate 16000 -c arctic20.fileids -di . -do . -ei wav -eo mfc -mswav yes
这样在当前文件夹下就会对每一个语音文件生成一个*.mfc后缀的特征文件,可能将其修改为*..mfc

  • 9、(离线识别英文)的Python脚本

这个识别.wav文件的语音,不需要安装流框架
#!/usr/bin/env python
import sys
#In Ubuntu 14.04.2, the pocketsphinx module error first import and ok the second import.
#The following code is a temporary fix
try:
import pocketsphinx
except:
import pocketsphinx
if __name__ == “__main__”:
hmdir = “/usr/share/pocketsphinx/model/hmm/en_US/hub4wsj_sc_8k”
lmdir = “/usr/share/pocketsphinx/model/lm/en_US/hub4.5000. DMP”
dictd = “/usr/share/pocketsphinx/model/lm/en_US/cmu07a.dic”

wavfile = sys.argv[1]
speechRec = pocketsphinx.Decoder( hmm = hmdir, lm = lmdir, dict = dictd)
wavFile = file( wavfile,’rb’)
speechRec.decode_raw( wavFile)
result = speechRec.get_hyp()
print “nnnDetected text:>”, result

  • 10、安装GStreamer framework语音包

$ sudo apt-get install gstreamer0.10-pocketsphinx
# 如果有问题,需要安装这个plugin使得获取GConf信息
$ sudo apt-get install gstreamer0.10-gconf
安装GStreamer Python binding从而python可以使用GStreamer APIs
$ sudo apt-get install python-gst0.10

  • 11、(在线识别英文)的Python脚本

#!/usr/bin/env python
import gobject
import sys
import pygst
# above should before gstreamer

pygst.require(‘0.10’)
gobject.threads_init()
import gst

#mode to handle kbd interuption
import signal

def signal_handle( signal, frame):
print “Ctrl+C pressed”
sys.exit( 0)

#Implementation of Speech recognition class
class Speech_Recog( object):

#Initializing gstreamer pipeline and pocket sphinx element
def __init__(self):
self.init_gst()
#The following code create a gstreamer pipeline with pipeline description.
#The required descriptors needed for the code is given as parameters.
def init_gst(self):
self.pipeline = gst.parse_launch(‘gconfaudiosrc ! audioconvert ! audioresample ‘ + ‘! vader name = vad auto-threshold = true ‘ + ‘! pocketsphinx

name = asr ! fakesink’)
#Accessing pocket sphinx element from gstreamer pipeline
asr = self.pipeline.get_by_name(‘asr’)
#Connecting to asr_result function when a speech to text conversion is completed
asr.connect(‘result’, self.asr_result)
#User can mention lm and dict for accurate detection
#asr.set_property(‘lm’, ‘/home/user/mylanguagemodel.lm’)
#This option will set all options configured well and can start recognition
asr.set_property(‘configured’, True)
#Pausing the GStreamer pipeline at first.
self.pipeline.set_state( gst.STATE_PAUSED)

#Definition of asr_result
def asr_result( self, asr, text, uttid):
#Printing the detected text
print “Detected Text =>”, text
#This function will start/ stop Speech recognition operation
def start_recognition( self):
vader = self.pipeline.get_by_name(‘vad’)
vader.set_property(‘silent’, False)
#Waiting for a key press to start recognition
raw_input(“Press any key to start recognition:>”)
#Start playing the pipeline
self.pipeline.set_state( gst.STATE_PLAYING)
#Waiting for stopping the recognition
raw_input(“Press any key to stop recognition: >”)
vader = self.pipeline.get_by_name(‘vad’)
#Setting silent property of VADER to True
vader.set_property(‘silent’, True)
#Pausing GStreamer pipeline
self.pipeline.set_state(gst.STATE_PAUSED)

if __name__ == “__main__”:
app_object = Speech_Recog()
signal.signal( signal.SIGINT, signal_handle)
while True:
app_object.start_recognition()

  • 12、ROS的node

1、安装ROS的pocketSphinx包
$ cd ~/catkin_ws
$ git clone https://github.com/mikeferguson/pocketsphinx
$ catkin_make
2、后面这两个可能需要
$ sudo apt-get install ros-indigo-audio-common
$ sudo apt-get install ros-indigo-pocketsphinx
2、测试
运行robocup节点
$ roslaunch pocketsphinx robocup.launch
订阅主题,查看识别结果
$ rostopic echo /recognizer/output
例如
j