2019-01-11 15:56:24 weixin_44328479 阅读数 8175
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    6114 人正在学习 去看看 杨波

简介

本文记录百度离线识别与讯飞离线语音识别,针对的是应用本身级别的。

百度语音离线识别集成

  1. 首先下载开发架包:bdasr_V3_20180801_d6f298a.jar,这个是离在线融合的SDK ;

  2. 导入so库:可在下载的demo中找到,复制到自己工程中同名的路径下
    在这里插入图片描述

  3. 需要百度开放平台上去申请 API Key 和 Secret Key,这是认证权限的必备信息,只有认证通过才可以继续使用语音功能,如语音唤醒,在线识别,离线识别等等。首先需要百度开放平台上去申请 API Key 和 Secret Key,这是认证权限的必备信息,只有认证通过才可以继续使用语音功能,如语音唤醒,在线识别,离线识别等等。
    在这里插入图片描述
    而鉴权认证就是要成功获取到AccessToken(Access Token 是用户身份验证和授权的凭证),而这个认证过程需要自己在应用中编写,之后会提到。
    将获取到的AppID、API Key 和 Secret Key添加到项目的配置文件中去;

  4. AndroidManifest.xml 文件的配置:
    设置权限(如果是Android 6.0 以上还需要获取动态权限,之后会说到)

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

设置APP_ID, APP_KEY, APP_SECRET

    <meta-data android:name="com.baidu.speech.APP_ID"
        android:value="9788136" />
    <meta-data
        android:name="com.baidu.speech.API_KEY"
        android:value="0GjQNO5H4pGPf9HyA3AmZEbz" />
    <meta-data
        android:name="com.baidu.speech.SECRET_KEY"
        android:value="db981ef3ec647ba8a09b599ad7447a24" />
  1. 注意事项:在申请API Key时需要设置应用包名,并且保证官网申请时的与app/bulid.gradle里的applicationId一致,否则会导致离线命令词或是唤醒报“no licenece”的错误。

离线识别实现

1.可以先准备本地词库和唤醒词库

2.基于SDK的使用:

  • 初始化EventManager类
 EventManager  asr = EventManagerFactory.create(context, "asr");//语音识别器
 EventManager  wp = EventManagerFactory.create(context, "wp");//语音唤醒器
  • 定义输出事件类
public class RecogResultManager implements EventListener{
    ...........
    
     /**
     * 回调事件
     */
    @Override
    public void onEvent(String name, String params, byte[] data, int offset, int length) {
        String logMessage = "name:" + name + "; params:" + params;
        Log.d(TAG, logMessage);
        switch (name) {
            case SpeechConstant.CALLBACK_EVENT_ASR_READY:
                // 引擎准备就绪,可以开始说话              
                break;
            case SpeechConstant.CALLBACK_EVENT_ASR_BEGIN:
                // 检测到用户的已经开始说话
                break;
            case SpeechConstant.CALLBACK_EVENT_ASR_END:
                // 检测到用户的已经停止说话
                break;
            case SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL:
                // 临时识别结果, 长语音模式需要从此消息中取出结果
                break;
              case SpeechConstant.CALLBACK_EVENT_ASR_FINISH:
                // 识别结束, 最终识别结果或可能的错误
                break;
            case SpeechConstant.CALLBACK_EVENT_ASR_LONG_SPEECH:
                // 长语音
                break;
            case SpeechConstant.CALLBACK_EVENT_ASR_VOLUME:
                //音量值 
                break;
            case SpeechConstant.CALLBACK_EVENT_ASR_AUDIO:
                if (data.length != length) {
                 //可能出错的地方:回调返回的数据有问题
                   Log.d(TAG, "internal error: asr.audio" +
                            " callback data length is not equal to length param");
                 .....
                }
                break;
            case SpeechConstant.CALLBACK_EVENT_WAKEUP_SUCCESS:
                //语音唤醒成功 
                break;
            case SpeechConstant.CALLBACK_EVENT_WAKEUP_ERROR:
                //语音唤醒失败
                break;
            .......

            default:
                break;
        }
    }
}    


  • 注册自己的输出事件类
asr.registerListener(eventListener);
wp.registerListener(eventListener);
  • 加载唤醒词库与离线词库
 /**
 - 加载唤醒词库
  */
    private void loadWakeup() {
        Map<String, Object> params = new HashMap<>();
        params.put(SpeechConstant.WP_WORDS_FILE, "assets://WakeUp.bin");
        //开始识别语音唤醒
        mWakeup.start(params);
    }
    
 /**
 - 加载离线词库
  */
    private void loadWakeup() {
       Map<String, Object> params = new LinkedHashMap<>();
       //设置此参数使用与语音唤醒后进入语音识别模式
        params.put(SpeechConstant.VAD, SpeechConstant.VAD_DNN);
        params.put(SpeechConstant.DECODER, 2);
        params.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH, "assets://baidu_speech_grammar.bsg");
       //设置唤醒到识别的停顿时间
        if (backTrackInMs > 0) {
            params.put(SpeechConstant.AUDIO_MILLS, System.currentTimeMillis() - backTrackInMs);
        }
        mRecognizer.cancel();
        //开始进行识别
        mRecognizer.start(params);
    }
     注:对于语音唤醒到识别有两种方案:
     方案1: backTrackInMs > 0,唤醒词说完后,直接接句子,中间没有停顿,
            开启回溯,连同唤醒词一起整句识别,推荐4个字 1500ms,backTrackInMs 最大 15000,即15s.
     方案2: backTrackInMs = 0,唤醒词说完后,中间有停顿,不开启回溯。唤醒词识别回调后,正常开启识别。
            官方demo里采用默认设置的是1500,本人demo中选择的是方案2,因为测试结果方案2的识别效果好一些,详见下面测试结果。
  • 查询权限,获取AccessToken
public void check() {
        appendLogMessage("try to check appId " + appId + " ,appKey=" + appKey + " ,secretKey" + secretKey);
        if (appId == null || appId.isEmpty()) {
              errorMessage = "appId 为空";
              fixMessage = "填写appID";
          }
        if (appKey == null || appKey.isEmpty()) {
                errorMessage = "appKey 为空";
                fixMessage = "填写appID";
          }
        if (secretKey == null || secretKey.isEmpty()) {
                 errorMessage = "secretKey 为空";
                  fixMessage = "secretKey";
         }
        try {
                checkOnline();
        } catch (UnknownHostException e) {
                infoMessage = "无网络或者网络不连通,忽略检测 : " + e.getMessage();
        } catch (Exception e) {
                errorMessage = e.getClass().getCanonicalName() + ":" + e.getMessage();
                fixMessage = " 重新检测appId, appKey, appSecret是否正确";
         }
 }

/**
 *  获取并校验token
 */
  public void checkOnline() throws Exception {
            String urlpath = "http://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id="
                    + appKey + "&client_secret=" + secretKey;
            URL url = new URL(urlpath);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(1000);
            InputStream is = conn.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder result = new StringBuilder();
            String line = "";
            do {
                line = reader.readLine();
                if (line != null) {
                    result.append(line);
                }
            } while (line != null);
           String res = result.toString();
           if (!res.contains("audio_voice_assistant_get")) {
                errorMessage = "appid:" + appId + ",没有audio_voice_assistant_get 权限,请在网页上开通\"语音识别\"能力";
                fixMessage = "secretKey";
                return;
            }
            appendLogMessage("openapi return " + res);
            JSONObject jsonObject = new JSONObject(res);
            String error = jsonObject.optString("error");
            if (error != null && !error.isEmpty()) {
                errorMessage = "appkey secretKey 错误" + ", error:" + error + ", json is" + result;
                fixMessage = " 重新检测appId对应的 appKey, appSecret是否正确";
                return;
            }
           String token = jsonObject.getString("access_token");
           if (token == null || !token.endsWith("-" + appId)) {
                errorMessage = "appId 与 appkey及 appSecret 不一致。
                appId = " + appId + " ,token = " + token;
                fixMessage = " 重新检测appId对应的 appKey, appSecret是否正确";
            }
        }
    }
  • 加载动态权限(Android 6.0以上需要)
    在主Activity中添加:

 private void initPermission() {
        String[] permissions = {Manifest.permission.RECORD_AUDIO,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.INTERNET,
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };
        ArrayList<String> toApplyList = new ArrayList<>();
       for (String perm : permissions) {
            if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, perm)) {
                toApplyList.add(perm);
                // 进入到这里代表没有权限.
            }
        }
        String[] tmpList = new String[toApplyList.size()];
        if (!toApplyList.isEmpty()) {
            ActivityCompat.requestPermissions(this, toApplyList.toArray(tmpList), 123);
        }
    }
    
@Override
   public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        // 此处为android 6.0以上动态授权的回调,用户自行实现。
    }
  • 控制识别/唤醒
   /**
    * 语音唤醒开始
    */
    public void start(Map<String, Object> params) {
        String json = new JSONObject(params).toString();
        wp.send(SpeechConstant.WAKEUP_START, json, null, 0, 0);
    }
    
    /**
     * 停止语音唤醒
     */
    public void stop() {
        wp.send(SpeechConstant.WAKEUP_STOP, null, null, 0, 0);
    }

    /**
     * 开始识别
     */
    public void start(Map<String, Object> params) {
        String json = new JSONObject(params).toString();
        asr.send(SpeechConstant.ASR_START, json, null, 0, 0);
    }
    
    /**
     * 提前结束录音等待识别结果。
     */
    public void stop() {
        if (!isInited) {
            throw new RuntimeException("release() was called");
        }
        asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
    }
    
    /**
     * 取消本次识别,取消后将立即停止不会返回识别结果。
     * cancel 与stop的区别是 cancel在stop的基础上,完全停止整个识别流程,
     */
    public void cancel() {
        if (!isInited) {
            throw new RuntimeException("release() was called");
        }
        asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
    }
  • 事件管理器退出,回收资源,不能一直占用着mic资源。
    /**
     * 释放语音唤醒资源
     */
    public void release() {
       if (wp== null) {
            return;
        }
        stop();
        wp.unregisterListener(eventListener);
        wp = null;
        isInited = false;
    }
   
    /**
     * 释放语音识别资源
     */
      public void release() {
        if (asr == null) {
            return;
        }
        cancel();
        asr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0);
        asr.unregisterListener(eventListener);
        asr = null;
        isInited = false;
    }

添加动作识别:

之前考虑是用数据库匹配识别结果,来找到相应的组件,但是demo里做得着急,只是通过管理activity,以activity和name为媒介来找到相应的组件,从而执行相应的动作。

public abstract class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        VrApplication.getInstance().addActivity(this);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        VrApplication.getInstance().removeActivity(this);
    }
}
public class VrApplication extends Application {

    private static final VrApplication INSTANCE = new VrApplication();

    private  List<BaseActivity> mActivities;

    private VrApplication() {}

    public static VrApplication getInstance() {
        return VrApplication.INSTANCE;
    }

    public  void addActivity(BaseActivity activity){
        if(mActivities == null){
            mActivities = new ArrayList<>();
        }
        mActivities.add(activity);
    }
    
      public  void removeActivity(BaseActivity activity){
        mActivities.remove(activity);
    }

    public List<BaseActivity> getActivities() {
        return mActivities;
    }

    /**
     * 关闭应用后需要清空管理
     */
     public  void finishAll(){
        for(BaseActivity activity : mActivities){
            if(! activity.isFinishing()){
                activity.finish();
            }
        }
    }
}

所有的界面activity需要继承BaseActivity,初始化组件时保存起来,界面销毁时clear()。

 private void initView() {
        mViews = new HashMap<>();
        EditText etCode = (EditText) findViewById(R.id.tv_point_code);
        Button action = (Button) findViewById(R.id.btn_action);
        mViews.put(etCode.getHint().toString(), etCode);
        mViews.put(action.getText().toString(), action);
    }

回调监听处理结果,进行确认组件去执行相应的动作:

public class RecogResultManager implements EventListener, IStatus {
     ...............
     
    /**
     * 回调事件
     */
    @Override
    public void onEvent(String name, String params, byte[] data, int offset, int length) {
           switch (name) {
                ........
                case SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL:
                     // 临时识别结果, 长语音模式需要从此消息中取出结果
                     handlePartial(params, data, offset, length);
                     break;
                case SpeechConstant.CALLBACK_EVENT_ASR_FINISH:
                     // 识别结束, 最终识别结果或可能的错误
                     handleFinish(params);
                     break;
                ........
                case SpeechConstant.CALLBACK_EVENT_WAKEUP_SUCCESS:
                     //语音唤醒成功
                     handleWpSuccess(name, params);
                     break;
                case SpeechConstant.CALLBACK_EVENT_WAKEUP_ERROR:
                     handleWpErro(name, params);
                     break;
          }
    } 
    ........
}               

处理语音唤醒,语音唤醒后,要切换开始进行语音识别:

private void handleWpMsg() {
        Map<String, Object> mParams = new LinkedHashMap<>();
        mParams.put(SpeechConstant.VAD, SpeechConstant.VAD_DNN);
        mParams.put(SpeechConstant.DECODER, 2);
        mParams.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH, BSGPATH);
         if (mBackTrackInMs > 0) {
            mParams.put(SpeechConstant.AUDIO_MILLS, System.currentTimeMillis() - mBackTrackInMs);
        }
        mRecognizer.cancel();
        mRecognizer.start(mParams);
 }

处理语音识别结果:

private void analysData(RecogResult recogResult) {
        String results = recogResult.getBestResult();
        //从缓存中获取当前的Activity
        BaseActivity activityInstance = UiUtil.getActivityInstance(mContext);
        if (activityInstance == null) {
            return;
        }
        Map<String, View> views = activityInstance.getViews();
        for (Map.Entry<String, View> entry : views.entrySet()) {
            if (results.contains(entry.getKey())) {
                action(entry.getValue(), results);
            }
        }
  }

执行动作:

 private void action(View value, String results) {
        if (value instanceof Button) {
            value.performClick();
        } else if (value instanceof EditText) {
            ((EditText) value).setText(results);
        }
 }

注意事项

1.即使只进行离线操作,第一次也需要进行联网进行认证授权才可以进行接下来的语音识别。
2. 不用时要及时释放,不能一直占用mic资源,影响其他使用。
3. 环境嘈杂时,识别率会很低,需要依赖降噪算法。
4.本demo针对一个应用来说,通过语音识别命令,并执行操作,跳转界面,点击操作,选择操作等,有一定的局限性,因为离线时,只能识别词库中的词,所以EditText或是TextView填写值的时候,可能没有用户所说的那个值,目前只是依赖在线识别来控制这块,还有待进一步研究。

demo下载地址:

链接: https://download.csdn.net/download/weixin_44328479/10910474.
Alt

2016-10-20 13:40:00 weixin_30287169 阅读数 24
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    6114 人正在学习 去看看 杨波

在人际交往中,言语是最自然并且最直接的方式之一。随着技术的进步,越来越多的人们也期望计算机能够具备与人进行言语沟通的能力,因此,语音识别这一技术也越来越受到关注。尤其,随着深度学习技术应用在语音识别技术中,使得语音识别的性能得到了显著提升,也使得语音识别技术的普及成为了现实。

 


 

以上是废话,下面开始正文。

 

 

自动语音识别技术,简单来说其实就是利用计算机将语音信号自动转换为文本的一项技术。这项技术同时也是机器理解人类言语的第一个也是很重要的一个过程。

 

为了进一步解释计算机如何实现语音到文字的转换这一过程,我先把目前比较主流的自动语音识别系统的整体框架贴出来,然后再一一简要地对各部分进行说明。

    当我们要对一段语音进行识别时,首先需要进行的是对语音特征的提取。这一步所做的工作其实就是从输入的语音信号(时域信号)中提取出可以进行建模的声学观测特征向量序列O。通俗地解释就是把需要识别的一段语音进行特征提取,之后得到了一组可以表征这一段语音的向量,后续对语音进行的一系列操作都是基于这组向量的。

    在得到了这组观测特征向量O之后,我们可以用一个公式来说明一下语音识别具体是要做一个什么样的事情:

W  = argmax P(W|O)

    这个公式含义很简单,就是说在给定一组观测向量O的条件下,找到一组词向量W使得P(W|O)的概率最大。这个也正是人听到一段语音的时候做的事情——找所有已知文字中和这段语音最匹配的。但是,依靠这个公式,我们是无法解决语音识别问题的。还需要利用贝叶斯定理对其进行转换,将其转换成我们能够分别进行建模求解的形式。转换如下:

W = argmaxP(W|O) = argmax P(O|W)P(W) / P(O)

    其中,P(O)是声学观测的先验概率,在自动语音识别过程中,由于输入的声学观测特征序列是固定的,可以认为上述公式中的P(O)是常量,因此P(O)在上述公式的最大化的过程中不起作用,可以忽略。那么我们现在只剩下P(O|W)和P(W)需要考虑。而在上述结构图中的声学模型和语言模型分别提供了对P(O|W)和P(W)进行计算的方法,下面分别简单介绍一下。

    首先是声学模型,其目的是提供一种方法,来对给定词w的声学观测特征序列O的似然度进行计算。(可以理解成给定一个词w,然后算目前这个特征向量是描述这个词的可能性有多大,也就是算P(O|W)),所以这个建模的任务就可以简单地理解成对每一个词建立一个描述概率分布的模型,该模型的输入是声学特征向量,输出则是一个概率(似然值),概率越高表示该声学特征越可能表示的是这个词。但是在实际的大词汇量语音识别任务中,如果对每一个词建立一个模型是很不现实的。因为词的数量非常多,而且经常会有新词出现。为了解决这个问题,声学模型通常不会直接对词进行建模,而是将词拆成字词序列,对字词进行建模。举个例子,汉语中的汉字有几万个,但是如果将汉字拆分成音标(跑 p ao),那么我们只需要用几十个音标就可以表示所有汉字的读音,就算考虑音调,我们也最多只需要几百个音标就足够了。然后,对音标进行建模,在将其拼接成汉字,就可以得到我们需要的p(O|W)同时却大大减少了建模的数量。因此,目前主流的声学建模方法一般采用对语音的基本单位——音子进行建模(音子与音标有区别,不一样,但可以利用音标对音子的概念进行理解)。

    刚刚在声学模型中提到了子词的概念,那么子词如何拼接成真正的词呢?这就需要给计算机一个规则,这个就是我们的发音词典。发音词典可以理解成一个词到音子的映射(简单理解成给定词,然后利用发音单元给它“注音”,例如:你好 n i h ao),系统通过查找发音词典就可以知道每个词是由哪些发音单元组成的了。

    再来说说语言模型,现在我们利用声学模型和发音词典可以搞定P(O|W)了,但是我们还需要知道P(W)要如何进行计算。语言模型就是在做这么一件事情。它提供了一种机制,来利用当前词之前的n个词来估计当前词是w的概率。举例来说,比如我们已经有了两个个词“我 是”,现在想知道接下来的词会是什么。很显然“我 是” 后面可以接很多词,比如“我是学生”,“我是猪”,“我是饮水机”等等。而语言模型的作用就是计算这些词出现的概率。因此,一个好的语言模型算得的“我是学生”的概率可能会比另两个高,因为“我是人”这句话更符合人们通常的说话习惯。这样,利用语言模型我们也找到了一种计算P(W)的方法。

    最后,我们利用上述的声学模型、语言模型和发音词典就可以构建起一个解码空间,之后利用解码器,结合每一组输入的语音特征向量在空间中进行搜索,找到一条最优的词序列,就是找到一条路径使得P(O|W)P(W)概率最大。那么,最终得到的这个词序列就是我们想要的识别结果。

 

 


 

 由于是第一次写博客,就先写篇小简介试试水,写的不好,中间也应该会有一些错误和不足,还望大家多提意见,多多指正 O(∩_∩)O

 

 

转载于:https://www.cnblogs.com/xpz-blog/p/5980555.html

2018-07-31 17:08:50 yibuerbusanbu 阅读数 3967
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    6114 人正在学习 去看看 杨波

1.前言:
本科毕业之后,开始了北漂,一直想从事一些偏上层方面的工作,开始找工作期间各种碰壁。可能自己c语言的基础还可以的原因,被现在的单位的引擎组招了过来,起初只是被用来干一些引擎的支持和测试,慢慢的开始接触到了语音识别等引擎的开发,所以利用自己在工作中所了解得在这里班门弄斧地谈谈语音识别,也是想工作进行总结。也欢迎大家指出错误和不足。
1.语音识别简介:
语音识别技术即AutomaticSpeechRecognition(简称ASR),是指将人说话的语音信号转换为可被计算机程序所识别的信息,从而识别说话人的语音指令及文字内容的技术。目前语音识别被广泛的应用于客服质检,导航,智能家居等领域。
2.语音识别过程:
在这里插入图片描述
语音识别大体上包含前端处理,特征提取,模型训练,解码四个模块。其中前端处理包括了,语音转码,高通滤波,端点检测等。
上图目前语音识别的基本流程,输入的语音数据流经过前端处理(语音格式转码,高通,端点检测),语音格式转码是将输入的语音数据转成pcm或者wav格式的语音,端点检测是检测出转码后语音中的有效语音,这样对解码速度和识别率上都会改善。经过前端处理之后的得到的分段语音数据送入特征提取模块,进行声学特征提取。最后解码模块对提取的特征数据进行解码,解码过程中利用发音字典,声学模型,语言模型等信息构建WFST搜索空间,在搜索空间内寻找匹配概率最大的最优路径,便得到最优的识别结果。
在其他章节中会详细介绍以上四个模块。
3.语音识别的学习:
由于语音识别本事就是一个非常大并且繁琐的工程,设计到知识面很广,目前我也在想如何把这个学习过程更加系统化,简单化。希望这一块能得到前辈的指点。
目前我再看这些书籍:
1).数学之美,这本书对整个语音识别过程以及各个模块讲的很详细,也很通俗易懂,是一本不错的语音识别入门的书。
2).语音信号处理,这本书对前端处理模块的学习有很大的帮助,由于是一本教材书籍,自己在有些地方看起来也很晦涩,目前也想在网上找一些相关网课看看,这样更加深理解,找到的话也会第一时间分享。
3).关于特征提起模块,网上有很多帖子写的都很详细,后面我也会整理一下。
4).解码和模型训练…未完!!!

2010-08-03 13:25:00 xieyan0811 阅读数 2939
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    6114 人正在学习 去看看 杨波

 

1.     语音识别一般使用三种方式

1)         方式一:调用语音识别库的程序做成带界面的程序,供其它程序使用intent调用

2)         方法二:应用程序自己调用语音识别库

3)         方式三:调用语音识别库的程序做成service,供其它应用使用

2.     android2.2对语音识别的内部支持

1)         frameworks/base/core/java/android/speech/*
语音的android框架支持(合语音合成和语音识别)

a)          RecognitionListener.java 用于支持对方式三的调用

b)         Recognizer*Intent                 用于支持对方式一的调用

c)          RecognitionService.java         用于支持对方式三的调用

d)         SpeechRecognizer.java 用于支持对方式三的调用

e)          srec目录
语音识别,它用于方式一二三真正功能的实现

                                       i.              MicrophoneInputStream.java 实现录音

                                      ii.              Recognizer.java   实现识别的接口

f)          tts目录
语音合成

2)         external/srec/*
语音识别的底层实现

3.     语音引擎:

1)         srec            android自带的语音识别工具

2)         simon         网上说该识别工具可移植到android

3)         pico            android自带的语音合成工具

4.     参考

1)         可参考语音拨号器应用的实现,源码在
packages/apps/VoiceDialer/

 

(转载请注明出处: http://xy0811.spaces.live.com/)

 

 

2012-12-08 09:34:06 lxlzhn 阅读数 5145
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    6114 人正在学习 去看看 杨波

语音识别:

       语音识别技术就是让机器通过识别和理解过程把语音信号转变为相应的文本或命令的高技术。它主要包括特征提取技术、模式匹配准则及模型训练技术三个方面。语音识别区别于声纹识别,后者尝试识别或确认发出语音的说话人而非其中所包含的词汇内容。语音识别技术的发展可参考http://baike.baidu.com/view/652891.htm。


       以下主要介绍PC端语音识别产品,现行产品还是分为两种:云语音识别和离线语音识别。

云语音识别:

1. html5语音输入标签直接支持语音输入,浏览器中的语音输入,未来语音识别的标准,由于是基于Google的语音库的,因此识别率还较低,需要浏览器支持(目前chrome 11及以上版本支持较好,IE和Firefox等暂不支持),实例:WebQQ中在chrome中打开有使用该语音识别 http://web.qq.com/

2. PC端的google输入法语音输入,这个和应该和chrome中的类似,都是要调用google的云语音库,由于google被墙的原因,再加上google更擅长处理英文,所以识别效果也还一般。

3. 科大讯飞语音云,中文语音合成和识别,目前国内较为成熟的中文语音识别,主要在移动端发力,最近也已经在PC端开始布局,java版,windows版,linux版,还有简单发布的半官方的flash版本(前面的三个PC版都是官网直接发布的,flash的截至2012-12-07还是在官方论坛上通过迅雷网盘发布,有失效时间,因此可能更新也会比较频繁),Web端开发需要flash支持或开发浏览器插件。

(1)研究了下Flash的控件的,暂时还是有很多问题,调用还是各种报错(科大讯飞+flash——语音识别时报错:Error #10202:套接字连接 和 长时间不点击报错: error#120106:通信沙箱安全错误;已提交官网论坛需求帮助,暂时没有收到回复),包括官网上给的演示实例也不能正常使用(有输入的提示,话筒会动,但是没有识别后的信息显示,也没有报错),不过随着时间推移,慢慢应该会变好。Flash版科大讯飞测试页面:http://open.voicecloud.cn/iat.php

 

(2) 基于windows包的ActiveX插件,只支持IE(研究了一下,很少搞ActiveX,没搞懂... 后来搞了下java版Swing图形界面的实例,测试了下识别效果还是不错的);chrome插件和firefox插件的还没看。

离线语音识别:

       离线的主要是关注了IBM ViaVoice,这个产品整体评价最好,只下载到for windows XP的9.0版本(可以到新浪爱问上搜索下载),10版本的据说是支持win7,不过没看到有破解版的流出,都是要线上购买收费的。在XP上试用了9版本的,感觉IBM的这个就是真的按照”特征提取技术、模式匹配准则及模型训练"来做的,安装到后面需要不断通过语音录入和设置等去训练该软件,以使得软件更加能够准确的识别操作者的语音,还可以做一些自定义设置和其他高级设置。和基于云的语音识别不太一样的是,IBM的不仅能够提供语音听写(即语音翻译成汉字),还能够借助该软件实际操作电脑,如说“网上冲浪”就会打开IE浏览器,还有类似的打开软件和文件夹等操作。识别率在不特别训练的情况下已经较高,如果根据个人的不断使用和偏好设置,据说识别率会更上一层楼——该软件属于智能软件,不断的积累会使软件内部的建模更加精准更加好用。缺点是:设置复杂,且更倾向于个人电脑使用,不适合像图书馆这种公用的电脑;非语音提示——可能是还未深入研究清楚,可设置的高级功能很多;且9.0版本语音库中的词句比较老旧,对于较新词汇不能很好识别,适合识别传统词汇——可能10版本的词库会比较新吧。

       另外,讯飞据说也有离线收费版的语音识别产品,由于没有相关软件,所以无法体验。已经按照官网论坛回复的向msp_support@iflytek.com发送邮件询问了解,暂无回复。

       总结,由于现行语音识别软件产品还是不能达到精确识别的程度,因此感觉还不能很好的商用,或者需要定制开发,或者需要深入研究下怎么样结合实际需求来配合使用。以上属于个人简单学习结果,仅供参考。

 

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