1.什么是OpenEars
OpenEars是面向iOS平台的一个离线的语音识别和text-to-speech(文字语音转换)开发工具包。因为是离线的,它无需象Siri那样需要和服务器进行网络连接。当然,还要强调一点的是,OpenEars主要是针对英语的。最重要的是,它是免费的。除了基本的免费功能,它还提供了可以用来扩展基本功能的付费插件,也即Politepix OpenEars插件。
使用OpenEars,可以在iPhone和iPad应用中轻松实现英语的语音识别和TTS(语音合成)功能,并可使用开源的CMU Pocketsphinx,CMU Flite,CMUCLMTK类库。
OpenEars 平台也是一个完整的开发平台,其中包含了免费的OpenEArs SDK,以及一些拓展的功能插件(付费)。
考虑到我朝开发人员多数是屌丝出身,这里先介绍免费的SDK,等大家熟悉了之后再自行探索付费功能插件。
对于iPhone本地应用来说,要实现高精确度的大容量词汇识别目前来说是非常困难的,即便是Siri也需要利用强大的服务器数据库来完成这一任务。不过Pocketsphinx(OpenEars所使用的开源语音识别引擎)能够做到在iPhone本地应用中根据环境和其它因素来识别英语词汇。
当前OpenEars的最新版本是1.2.5,下载地址:http://www.politepix.com/wp-content/uploads/OpenEarsDistribution.tar.bz2
2.OpenEars的功能特性
OpenEars目前有以下的功能特性:
1. 在后台线程中连续监听,并根据需要暂停或继续语言处理,而这些操作在iPhone4中仅占用4%的CPU(包括语言解码,语音合成)。
2. 支持9种语音类型,包括男性和女性,速度和质量在一定的范围内,并可在使用的过程中更改。
3. 可以更改语音合成的音高,音速和变化。
4. 判断当前耳机是否在插孔中,然后仅当耳机在插孔中时才继续语言识别。
5. 支持蓝牙语音设备(实验中)。
6. 语音识别和语音合成的结果可以被当前应用的任一类所共享
7. 支持JSGF语法
8. 根据NSArray或NSString中的输入来动态生成新的ARPA语言模型
9. 动态切换ARPA语言模型或JSGF语法
10. 测试已有的录音
11. 可以通过标准的Objective-C方法进行交互
12. 所有的语音识别和语音合成功能均在内存中完成,无需写入到音频文件中再读取。
13. 包装在一个Cocoa标准风格的框架中
注意:
在使用OpenEars的时候,尽量直接在设备上测试应用,在模拟器上的识别精度会有所下降。
此外,在Xcode4.5中苹果已经删除armv6架构编译。如果需要为armv6设备编译,可以使用OpenEars之前的旧版本,但该版本不会继续更新,也无法用于编译armv7s设备。http://www.politepix.com/wp-content/uploads/OpenEarsDistributionLegacy.tar.bz2
3.OpenEars的安装和使用
(1)首先下载框架:
http://www.politepix.com/wp-content/uploads/OpenEarsDistribution.tar.bz2
(2)在Xcode中创建自己的应用,并添加AudioToolbox和AVFoundation框架。
(3)将所下载压缩包中的Frameworks文件夹拖到项目中
接下来呢?~现在就已经可以开始使用OpenEars了。
为了熟悉它的基本功能,可以先尝试运行示例项目。因为示例项目支持ARC,所以最好使用最新的Xcode版本。
4. OpenEars示例项目简介
在我第一次使用OpenEars的示例项目时,因为受了Siri的影响,于是尝试说了一大堆,结果发现这个简单示例项目支持的是词汇识别,而不是句子的识别。还是颇有些失望的。
不过最起码它还是可以识别出你所说的单词,精确度还很高。
在Xcode中打开OpenEarsSampleApp,项目的结果非常简单,首先是OpenEars的特有框架,然后是AudioToolbox和AVFoundation这两个标准框架,当然还有其它几个几乎每个项目都会用到的框架。
随便打开一个.xib文件,会看到项目的布局。
两个文本框,两个标签,还有四个按钮。
打开ViewController.h,会看到它遵循OpenEarsEventsObserverDelegatex协议。在头文件里面定义了多个方法,其中四个IBAction方法是我们重点要了解的。
切换到ViewControlller.m,来看看几个方法的实现代码。
最重要的当然是startListening方法,只有一行代码,startListeningWithLanguageModelAtPath:dictionaryAtPath:languageModelIsJSGF方法需要知道所使用的语法文件,词典文件,以及该语法是否是JSGF。在单个语音识别循环中,只能使用JSGF或ARPA语法文件中的一种,而不能在两种类型中切换。
ARPA语法通常是.languagemodel或.DMP后缀的文件,而JSGF语法则是.gram后缀的文件。
如果你只是想识别某个单独的语音wav文件,可以使用以下方式:
NSString *wavPath = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] resourcePath], @"test.wav"];
[self.pocketsphinxController runRecognitionOnWavFileAtPath:wavPath usingLanguageModelAtPath:self.pathToGrammarToStartAppWith dictionaryAtPath:self.pathToDictionaryToStartAppWith languageModelIsJSGF:FALSE]; // Starts the recognition loop.
示例中的方法适用于进行连续语音识别。
在viewDidLoad方法中主要是指定了startListening 方法中所使用的参数,然后调用了startListening方法和startDisplayingLevels方法。
这里使用的默认词典和语法是OpenEars1.dic和OpenEras1.languagemodel(在Frameworks文件中自带的)。
需要注意的是startDisplayingLevels方法是这个示例项目中特有的方法,这里就不详细介绍了。
此外就是OpenEarsEventsObserver的协议实现方法,稍作修改就可以在其它项目中使用。
当用户说出change model后,就会将词典和语法切换到动态生成的词典,也就是languageArray中的几个单词。
在设备上运行项目后,首先看到如下界面:默认的词典里面只支持Backward,change,forward,go,left,model,right,turn几个单词。当你说change model后,就切换到由程序数组动态生成的词典,就可以支持change,model,Monday,Tuesday,…Sunday, QUIDNUNC。
为了进一步测试,我尝试把viewDidLoad里面的词组更换为:
NSArray *languageArray = [[NSArray alloc] initWithArray:[NSArray arrayWithObjects: // All capital letters.
@"APPLE",
@"Steve Jobs",
@"Tim Cook",
@"MICROSOFT",
@"FOOD",
@"MONEY",
@"GAME",
@"IPHONE",
@"SIRI",
nil]];
再次运行测试,当说出 change model 的指令后,程序对于新的词组都可以识别并输出,如图:
说明这个识别是与大小写无关的。
然后来测试对句子的识别,将viewDidLoad中的词组修改为如下:
NSArray *languageArray = [[NSArray alloc] initWithArray:[NSArray arrayWithObjects: // All capital letters.
@"APPLE",
@"Steve Jobs",
@"Tim Cook",
@"I love Apple",
@"I am hungry",
@"I really really need money",
@"I'm not a baby",
@"IPHONE",
@"SIRI",
nil]];
再次测试,基本上识别精度仍然很高,但连续识别的时候容易跟之前的句子弄混,不过这个体验问题不难解决。
这样的话,示例项目的目的已经基本上达到。我们对示例项目做一些修改就可以为自己所用。