1. 程式人生 > >語音識別,語義理解一站式解決之智慧照相機(人臉識別,olami)

語音識別,語義理解一站式解決之智慧照相機(人臉識別,olami)

olami sdk實現了把錄音或者文字轉化為使用者可以理解的json字串從而實現語義理解,使用者可以定義自己的

語義,通過這種方式可以實現使用者需要的語義理解。前面寫了兩篇語音識別,語義理解的博文,分別是語音

線上聽書和語音記帳軟體,本篇是語音智慧照相機。

1.智慧照相機的功能

手機後攝像頭畫素比較高,如果用後設想頭對準自己自拍,那麼看不到螢幕的情況下怎麼知道

自己在不在鏡頭中呢?而本篇做的智慧照相機就可以為您解決這個問題。

想要做的是這樣一個照相機app,可以語音切換攝像頭,人臉識別並語音播報識別的人臉是否在螢幕中央,

是偏向哪裡,當人臉居中的時候,提示使用者可以拍照了,使用者說“拍照”,“茄子”就會自動抓拍並儲存圖

片在手機中。

抓了兩張應用執行時的圖片:
這裡寫圖片描述

這裡寫圖片描述

2.eclipse中的lib目錄結構如下

這裡寫圖片描述

assets下面的事tts播報的資原始檔
libs目錄下,
libtts.so tts播報所需的庫檔案
libspeex.so 語音識別所需的庫檔案
libolamsc.so 語音識別所需的庫檔案

tts.jar tts播報所需的庫檔案
voicesdk_android.jar 語音識別所需的庫檔案

3.AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.olami" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14" /> <uses-permission android:name="android.permission.RECORD_AUDIO"
/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.CAMERA" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>

需要錄音,網路,讀寫sd卡,拍照等許可權。

4.layout佈局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <SurfaceView android:id="@+id/sView" 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content"/> 

        <com.olami.FaceView
            android:id="@+id/faceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </FrameLayout>                    

    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"  
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="開始" />
</RelativeLayout>

在surfaceview中自定義了一個FaceView,faceview用來顯示抓拍的人臉。
螢幕最下方有個button,因為這個版本暫時不支援語音喚醒功能(後續新增後再更新),新增一個button用於使用者想隨時說拍照的時候點選觸發用。

5.MainActivity.java 和FaceView.java

- 1.MainActivity.java

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_camera);

        initHandler();//用於處理錄音狀態回撥的訊息

        initView(); //初始化介面

        initViaVoiceRecognizerListener(); //初始化olami語音回撥監聽

        init();  //初始化olami語音識別sdk

        initTts(); //初始化tts語音播報

        DisplayMetrics dm = new DisplayMetrics();//定義DisplayMetrics物件
        getWindowManager().getDefaultDisplay().getMetrics(dm);//取得視窗屬性
        mScreenCenterx = dm.widthPixels/2;//視窗的寬度
        mScreenCentery = dm.heightPixels/2; //視窗的高度
    }

以下是olamisdk的初始化

public void init()
{
        mOlamiVoiceRecognizer = new OlamiVoiceRecognizer(MainActivity.this);
        TelephonyManager telephonyManager=
                                   (TelephonyManager) this.getSystemService(
                                    this.getBaseContext().TELEPHONY_SERVICE);
        String imei=telephonyManager.getDeviceId();
        mOlamiVoiceRecognizer.init(imei);//設定身份標識,可以填null

        //設定識別結果回撥listener
        mOlamiVoiceRecognizer.setListener(mOlamiVoiceRecognizerListener);

        //設定支援的語音型別,優先選擇中文簡體        
        mOlamiVoiceRecognizer.setLocalization(
                           OlamiVoiceRecognizer.LANGUAGE_SIMPLIFIED_CHINESE);
         mOlamiVoiceRecognizer.setAuthorization(
               "51a4bb56ba954655a4fc834bfdc46af1",
               "asr",
               "68bff251789b426896e70e888f919a6d",
               "nli");
        //註冊Appkey,在olami官網註冊應用後生成的appkey
        //註冊api,請直接填寫“asr”,標識語音識別型別
        //註冊secret,在olami官網註冊應用後生成的secret
        //註冊seq ,請填寫“nli”   

    //錄音時尾音結束時間,建議填//2000ms         
    mOlamiVoiceRecognizer.setVADTailTimeout(2000);
    //設定經緯度資訊,不願上傳位置資訊,可以填0 
    mOlamiVoiceRecognizer.setLatitudeAndLongitude(
                                         31.155364678184498,121.34882432933009); 
}

定義OlamiVoiceRecognizerListener,此處程式碼就不貼了。

onError(int errCode)//出錯回撥,可以對比官方文件錯誤碼看是什麼錯誤
onEndOfSpeech()//錄音結束
onBeginningOfSpeech()//錄音開始
onResult(String result, int type)//result是識別結果JSON字串
onCancel()//取消識別,不會再返回識別結果
onUpdateVolume(int volume)//錄音時的音量,1-12個級別大小音量

以下是handler訊息處理,包含語義解析

private void initHandler()
    {
        mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg)
            {
                switch (msg.what){
                case MessageConst.CLIENT_ACTION_START_RECORED:
                    mBtnStart.setText("錄音中");
                    break;
                case MessageConst.CLIENT_ACTION_STOP_RECORED:
                    mBtnStart.setText("識別中");
                    break;
                case MessageConst.CLIENT_ACTION_CANCEL_RECORED:
                    mBtnStart.setText("開始");
                    break;
                case MessageConst.CLIENT_ACTION_ON_ERROR:
                    mBtnStart.setText("開始");
                    break;
                case MessageConst.CLIENT_ACTION_UPDATA_VOLUME:
                    //mTextViewVolume.setText("音量: "+msg.arg1);
                    break;
                case MessageConst.SERVER_ACTION_RETURN_RESULT:
                    mBtnStart.setText("開始");
                    try{
                        String message = (String) msg.obj;
                        String input = null;
                        JSONObject jsonObject = new JSONObject(message);
                        JSONArray jArrayNli = 
                        jsonObject.optJSONObject("data").optJSONArray("nli");
                        JSONObject jObj = jArrayNli.optJSONObject(0);
                        JSONArray jArraySemantic = null;
                        if(message.contains("semantic"))
                        {
                          jArraySemantic = jObj.getJSONArray("semantic");
                          String modifier = 
                              jArraySemantic.optJSONObject(0).optJSONArray(
                                                   "modifier").optString(0);
                          if("take_photo".equals(modifier))
                              capture();    
                          else if("switch_camera".equals(modifier))
                              switchCamera();
                        }
                        else{
                          Log.i("ppp","result error");
                        }
                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                    }                   
                    break;  
                case MessageConst.CLIENT_ACTION_UPDATA_FACEDECTION_DATA:
                    if(mIsRecording)
                        break;
                    RectF rect = (RectF) msg.obj;
                    mLeft = rect.left;
                    mRight = rect.right;
                    mTop = rect.top;
                    mBottom = rect.bottom;
                    float centerx = mLeft +(mRight - mLeft)/2;
                    float centery = mTop + (mBottom-mTop)/2;
                    String promptString = "";
                    if(centerx<mScreenCenterx && Math.abs(mScreenCenterx-centerx) >100)
                        promptString = "位置偏左,";
                    else if((centerx > mScreenCenterx)&&
                                            (Math.abs(centerx -mScreenCenterx)>100))                
                        promptString = "位置偏右,";
                    if((centery < mScreenCentery)&&(
                                              Math.abs(mScreenCentery-centery) >200))
                    {
                        if("".equals(promptString))
                            promptString = "位置偏上";
                        else
                            promptString += "並且偏上";
                    }
                    else if((centery > mScreenCentery)&&
                    (Math.abs(centery -mScreenCenterx)>200))
                    {
                        if("".equals(promptString))
                            promptString = "位置偏下";
                        else
                            promptString += "並且偏下";
                    }
                    if("".equals(promptString))
                    {
                        promptString = "位置已經居中,可以拍照了";
                        mIsCenter = true;
                    }
                    else
                    {
                        mIsCenter = false;
                    }

                    ITtsListener ttsListener = new ITtsListener()
                    {

                        @Override
                        public void onPlayEnd() {
                            if(mIsCenter)
                            {
                                if(mOlamiVoiceRecognizer != null)
                                    mOlamiVoiceRecognizer.start();  
                            }
                        }

                        @Override
                        public void onPlayFlagEnd(String arg0) {

                        }

                        @Override
                        public void onTTSPower(long arg0) {

                        }

                    };
                    TtsPlayer.playText(MainActivity.this, 
                          promptString, ttsListener,Tts.TTS_SYSTEM_PRIORITY);   
                    break;
                }
            }
        };
    }

在MessageConst.SERVER_ACTION_RETURN_RESULT訊息中,通過解析伺服器返回的json字串,可以找到modifier這個欄位的值,如果是take_photo表示拍照,如果是switch_camera表示切換攝像頭。

當用戶說拍照或者茄子的時候,伺服器返回如下json字串:

[
  {
    "desc_obj": {
      "status": 0
    },
    "semantic": [
      {
        "app": "camera",
        "input": "拍照",
        "slots": [

        ],
        "modifier": [
          "take_photo"
        ],
        "customer": "58df512384ae11f0bb7b487e"
      }
    ],
    "type": "camera"
  }
]

這個拍照,茄子等語法都是自己定義的,詳細請看:

  • 2.人臉識別FaceView.java
public class FaceView extends View {
    private Camera.Face[] mFaces;
    private Paint mPaint;
    private Matrix matrix = new Matrix();
    private RectF mRectF = new RectF();
    private Handler mHandler;
    private long mCurrentTime;
    public void setFaces(Camera.Face[] faces) {
        mFaces = faces;
        invalidate();
    }

    public FaceView(Context context) {
        super(context);
        init(context);
    }

    public FaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public FaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    public void init(Context context) {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(5f);
        mPaint.setStyle(Paint.Style.STROKE);

    }

    public void setHandler(Handler handler)
    {
        mHandler = handler;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mFaces == null || mFaces.length < 0) {
            return;
        }
        //準備矩形框
        MainActivity.prepareMatrix(matrix, false, 270, getWidth(), getHeight());
        canvas.save();
        matrix.postRotate(0);
        canvas.rotate(-0);
        RectF tempRectF = new RectF();
        long tempTime = System.currentTimeMillis();
        for (int i = 0; i < mFaces.length; i++) {
            mRectF.set(mFaces[i].rect);//獲取face矩形框值
            float temp = mRectF.top;
            mRectF.top = -mRectF.bottom;
            mRectF.bottom = - temp;  //上下交換         
            matrix.mapRect(mRectF);
            canvas.drawRect(mRectF, mPaint);//繪製矩形框
            tempRectF.set(mRectF);
            if((mCurrentTime == 0) ||((tempTime-mCurrentTime)/1000) >= 4)
            {//超過4秒,傳送一次識別face矩形框值
                mHandler.sendMessage(mHandler.obtainMessage(
                MessageConst.CLIENT_ACTION_UPDATA_FACEDECTION_DATA, tempRectF));
                mCurrentTime = tempTime;
            }
            Log.i("ppp","mRectF.left = "+mRectF.left+"   mRectF.right = "+mRectF.right);
        }
        canvas.restore();
    }
}

自定義FaceView中,由於旋轉了270度,所以需要face矩形框上下值進行交換,不然人臉識別總是左右或者上下不能追蹤。每隔4秒傳送一次矩形框的值,在MainActivity.java的handler中收到這個訊息並進行是否居中的判斷。

case MessageConst.CLIENT_ACTION_UPDATA_FACEDECTION_DATA:
    if(mIsRecording)
        break;
    RectF rect = (RectF) msg.obj;
    mLeft = rect.left;
    mRight = rect.right;
    mTop = rect.top;
    mBottom = rect.bottom;//儲存上下左右的矩形框值
    float centerx = mLeft +(mRight - mLeft)/2;//獲取矩形框橫向中心點位置
    float centery = mTop + (mBottom-mTop)/2;//獲取矩形框縱向中心點位置
    String promptString = "";
    if(centerx<mScreenCenterx && Math.abs(mScreenCenterx-centerx) >100)
        promptString = "位置偏左,";
    else if((centerx > mScreenCenterx)&&
                            (Math.abs(centerx -mScreenCenterx)>100))                
        promptString = "位置偏右,";
    if((centery < mScreenCentery)&&(
                              Math.abs(mScreenCentery-centery) >200))
    {
        if("".equals(promptString))
            promptString = "位置偏上";
        else
            promptString += "並且偏上";
    }
    else if((centery > mScreenCentery)&&
    (Math.abs(centery -mScreenCenterx)>200))
    {
        if("".equals(promptString))
            promptString = "位置偏下";
        else
            promptString += "並且偏下";
    }
    if("".equals(promptString))
    {
        promptString = "位置已經居中,可以拍照了";
        mIsCenter = true;
    }
    else
    {
        mIsCenter = false;
    }

    ITtsListener ttsListener = new ITtsListener()
    {

        @Override
        public void onPlayEnd() {
            if(mIsCenter)
            {
                if(mOlamiVoiceRecognizer != null)
                    mOlamiVoiceRecognizer.start();  
            }
        }

        @Override
        public void onPlayFlagEnd(String arg0) {

        }

        @Override
        public void onTTSPower(long arg0) {

        }

    };
    TtsPlayer.playText(MainActivity.this, 
          promptString, ttsListener,Tts.TTS_SYSTEM_PRIORITY);   
    break;

可以獲得螢幕的中心點和人臉識別的矩形框的中心點,對比橫向和縱向的中心點大小和絕對值差,當橫向的值差100畫素以上就認為橫向不居中,並且根據大小分居左和居右,縱向大小差值在200畫素以上認為縱向不居中,並且根據大小分偏上和偏下,這個100,200畫素值使用者可以自己調節到合適的值。

呼叫TtsPlayer.playText提示,當播報結束後回撥到onPlayEnd() ,如果居中那麼已經提示使用者可以拍照了,此時啟動錄音程式,使用者不用點選button也不用喚醒,只許說拍照或者茄子就可以拍照了。

6.原始碼下載連結

7.相關連結

相關推薦

語音識別語義理解一站式解決智慧照相機(人臉識別,olami)

olami sdk實現了把錄音或者文字轉化為使用者可以理解的json字串從而實現語義理解,使用者可以定義自己的 語義,通過這種方式可以實現使用者需要的語義理解。前面寫了兩篇語音識別,語義理解的博文,分別是語音 線上聽書和語音記帳軟體,本篇是語音智慧照相機

語音識別語義理解一站式解決二(android,olami)

前言 國內語音識別技術已有多家,而olami不僅在語音識別上準確率較高,更重要的是在語義理解上十分強大,本文用olami sdk做了一個記賬demo(記賬部分程式碼參考開原始碼),這個demo可以語音新增不同消費記錄,查詢當天,當月消費情況,刪除消費列

語音識別語義理解一站式解決(android平臺&olami sdk)

olami sdk實現了把錄音或者文字轉化為使用者可以理解的json字串從而實現語義理解,使用者可以定義自己的語義,是不是很強大?本文講述怎麼自定義語義,以及如何解析自定義語義。 本文使用olami sdk做了一個線上聽書的demo,使用者只需類似“我想

用Kotlin開發android平臺語音識別語義理解應用(olamisdk)

本文使用Kotlin開發android平臺的一個語音識別方面的應用,用的是尤拉密開放平臺olamisdk。 1.Kotlin簡介 Kotlin是由JetBrains建立的基於JVM的程式語言,IntelliJ正是JetBrains的傑作,而android

大資料24小時:中國平安推出區塊鏈解決方案“壹賬鏈”雲從科技釋出3D結構光人臉識別技術

【資料猿導讀】釋出3D結構光人臉識別技術;計算機視覺創企雲從科技對外發布3D結構光人臉識別技術;

CVFC:人臉識別判斷相似度極高的國內外明星根據人工智慧演算法(AP雲)預測判別是否為同一個人

CV之FC:人臉識別之判斷相似度極高的國內外明星根據人工智慧演算法(AP雲)預測判別是否為同一個人      根據美國人口調查局的估計,截至到2013年1月4日,全世界有70.57億人。美國人口調查局的資料顯示全球人口在2012年3月12日突破70億;而聯合國人

OpenCv (圖片人臉識別)和 (攝像頭讀入)

先來張人臉識別效果圖: 1、概述 人臉識別,是基於人的臉部特徵資訊進行身份識別的一種生物識別技術。用攝像機或攝像頭採集含有人臉的影象或視訊流,並自動在影象中檢測和跟蹤人臉,進而對檢測到的人臉進行臉部的一系列相關技術,通常也叫做人像識別、面部識別。

Scikit-learn例項Pca+Svm人臉識別(AT&T資料集)

from __future__ import print_function from time import time import logging import matplotlib.pyplot as plt import cv2 from numpy import * from sklearn.mo

基於MATLAB運用PCA+SVM的特徵臉方法人臉識別

%% %主程式,程式從此開始 clc,clear npersons=40;%選取40個人的臉 global imgrow; global imgcol; imgrow=112; imgcol=92; %% %讀取訓練資料 disp('讀取訓練資料...') [f_matrix,t

程序猿福利來啦神目AI開放平臺免費送人臉識別SDK啦

平臺 text ffffff 程序 col src 人臉識別 技術 ces 程序猿福利來啦,神目AI開放平臺免費送人臉識別SDK啦

人臉識別智慧駕校—人臉識別門禁考勤機

人臉識別智慧駕校 著社會經濟的不斷髮展,現如今人們的生活節奏也越來越快。人們對於日常出行的需求也不斷增加,人手一本駕駛證已然成為現代生活中的技能標配。因此近年來人們對於駕駛證考試的需求也在不斷的增多,全國各地的駕校也遍地開花。駕車出行,往往關乎人身安危,因此每一位駕駛員需要經過嚴謹的學習、嚴苛的考試才能

雲棲大會人臉識別閘機【技術亮點篇3】--人臉識別閘機擺閘可達500萬次

雲棲大會人臉識別閘機【技術亮點篇3】–人臉識別閘機擺閘可達500萬次 人臉識別檢票閘機,已經開始廣泛的應用在全國各大展覽會、會議等人員進出通道場所,依照其外觀型別也叫翼閘人臉識別閘機。檢測報告中顯示:全高轉閘為IP54,翼閘為IP54,翼閘可達500萬次,擺閘可達500萬次。 雲棲大會

深度學習與人臉識別系列(3)__基於VGGNet的人臉識別系統

作者:wjmishuai 1.引言 本文中介紹的人臉識別系統是基於這兩篇論文: 第一篇論文介紹了海量資料集下的圖片檢索方法。第二篇文章將這種思想應用到人臉識別系統中,實現基於深度學習的人臉識別。 2.關於深度學習的簡要介紹     現階段為止,對

4G LTE 網只能提供數據服務不能承載語音通話該怎麽理解

通話 組網 相關 ads 殺手 是不是 曾經 huawei lte-a 轉:http://www.qbiao.com/16776.html 這個問題要從移動核心網的角度來理解。我們平時說的WCDMA、TD-SCDMA、TD-LTE其實通常指空口技術,即從手機到基站的通信技術

80端口被屏蔽解決方法80端口穿透NAT端口映射技術

sdn 映射 font statistic -c alt sso avi text 介紹一種NAT端口映射技術應用,達到80端口穿透目的,解決80端口被屏蔽的問題,也是80端口被屏蔽解決方法中經常用到的。 80端口穿透類似80端口轉發,因為80端口被屏蔽,在數據層面來說是

機器學習路--機器學習演算法一覽應用建議與解決思路

作者:寒小陽 時間:2016年1月。 出處:http://www.lai18.com/content/2440126.html 宣告:版權所有,轉載請聯絡作者並註明出處 1.引言提起筆來寫這篇部落格,突然有點愧疚和尷尬。愧疚的是,工作雜事多,加之懶癌嚴重,導致這個系列一直沒有更新,向關注該系列的同學們

unity 對接訊飛window平臺語音識別語音合成記錄

最近記性越來越差,必須得把踩過的坑寫下來,防止重複踩坑的出現。 主要參考了部落格:https://blog.csdn.net/qq_39993352/article/details/80545422和語音識別的案例原始碼:https://github.com/3wz/IFlySDKForUn

人工智慧Python人臉識別技術人人都能做識別

一、環境搭建 1.系統環境 Ubuntu 17.04 Python 2.7.14 pycharm 開發工具 2.開發環境,安裝各種系統包 人臉檢測基於dlib,dlib依賴Boost和cmake 在windows中如果要使用dlib還是比較麻煩的,如果想省時間可以在an

Tensorflow編程基礎Mnist手寫識別實驗+關於cross_entropy的理解

ast 大學時光 default ice red con graph cast utf-8 好久沒有靜下心來寫點東西了,最近好像又回到了高中時候的狀態,休息不好,無法全心學習,惡性循環,現在終於調整的好一點了,聽著純音樂突然非常傷感,那些曾經快樂的大學時光啊,突然又慢慢的一

華為手機WebView長按不能複製記一次少見奇葩bug解決

風起 接到反饋,說是之前一個老專案的詳情頁(html)長按不能複製了(華為mate9),uh…不記得需求裡有長按複製功能,不過現在原生webview是支援長按複製的,所以就是個預設需求了,那這個bug是要改的。 拿手邊的華為和小米試了一下,的確不能複製,然後到模擬器上跑了下,uh…長