安卓平台使用pocketSphinx離線語音識別


版權聲明:本文為elecdog原創文章,可以轉載,但必須在明確位置注明出處!謝謝合作。

關於語音識別,國內已經有比較好的公司推出相關的服務了,比如百度免費的離在線融合語音識別以及訊飛收費的在線和離線語音識別服務。這里不作過多介紹,需要的同學可以直接去官網閱讀接入文檔。這里要介紹的是一個離線語音識別的開源項目——CMU PocketSpinnx,在安卓開發中的使用。在智能家居 APP 開發中常需要在沒法聯網的設備識別一些比較簡單的命令詞,百度的離在線融合語音識別識別率還不錯,不過在設備連接局域網的情況下仍然優先使用在線識別,導致識別時間太長或者轉換不過來,訊飛離線語音識別沒有使用過,因為是收費的,而且對於個人開發者價格也不便宜,相比較之下,PocketSpinnx則是完全離線的語音識別,只要按照要求部署項目,識別率也差強人意。

首先我們可以通過 PocketSpinnx 官網的介紹來了解該離線語音識別項目的工作原理,能夠加深對項目使用的理解。下面我們一步一步來把PocketSpinnx的離線語音識別功能引入到我們自己的項目中來。

獲取語言模型

首先我們需要把想要識別的命令詞編寫成命令集,打開 Sublime Text 新建 txt 文件,編碼采用 utf-8,每一行寫一個命令詞,如圖所示:

命令集

然后訪問網址 http://www.speech.cs.cmu.edu/tools/lmtool-new.html 生成語言模型(國內訪問不穩定,需自備梯子),點擊選擇文件,選擇剛才編寫的命令集文件 command.txt,然后點擊COMPILE KNOWLEDGE BASE按鈕就可以生成語言模型,如圖:語言模型

這里生成了好幾個文件,我們可以把整個 .tgz 文件下載下來解壓縮,其中得到的 .lm 文件就是我們需要的語言模型。

獲取字典模型

字典模型的作用,就是告訴語音識別器中文的發音,這樣他才能認得中文,字典模型很簡單,首先到 PocketSpinnx 的資源網盤,進入 Mandarin 文件夾,下載一個后綴為 .dic 的文件,里面涵蓋了很多普通話的發音,查找到我們的命令詞,找不到完整命令詞的也可以找單個字的發音,然后參考這個 .dic 文件的格式,在上一步獲取到的 .lm 語言模型文件中還有一個 .dic 文件,補充完整這個 .dic 文件的發音,如圖所示:字典模型

這樣字典模型就算是完成了。

獲取聲學模型

同樣是在資源網盤的 Mandarin 文件夾下,下載 .tar.bz2 的壓縮文件解壓后,得到如下聲學模型文件:聲學模型

在項目中導入接口

在以上必要文件都准備好之后,我們可以在 PocketSpinnx 開源的安卓 demo中直觀地了解具體的用法,項目結構如圖所示:項目結構

我們可以把 demo 中的 aars 和 models 導入到我們自己的項目中,快速集成相關接口。demo 中 en-us-ptm 中的是英文的聲學模型,為了能夠識別中文,我們可以依樣畫葫蘆新建一個 ptm-zh 文件夾,放入我們前面獲取的普通話聲學模型。同時,還需要把我們的語言模型和字典模型放進來,准備工作算是完成了。

獲取識別器

現在我們已經可以在項目中調用相關的 API 了,首先需要獲取最重要的語音識別器類SpeechRecognizer,如demo中的代碼:

    private void runRecognizerSetup() {
        // Recognizer initialization is a time-consuming and it involves IO,
        // so we execute it in async task
        new AsyncTask<Void, Void, Exception>() {
            @Override
            protected Exception doInBackground(Void... params) {
                try {
                    Assets assets = new Assets(PocketSphinxActivity.this);
                    File assetDir = assets.syncAssets();
                    setupRecognizer(assetDir);
                } catch (IOException e) {
                    return e;
                }
                return null;
            }

            @Override
            protected void onPostExecute(Exception result) {
                if (result != null) {
                    ((TextView) findViewById(R.id.caption_text))
                            .setText("Failed to init recognizer " + result);
                } else {
                    switchSearch(KWS_SEARCH);
                }
            }
        }.execute();
    }

    private void setupRecognizer(File assetsDir) throws IOException {
        // The recognizer can be configured to perform multiple searches
        // of different kind and switch between them

        recognizer = SpeechRecognizerSetup.defaultSetup()
                .setAcousticModel(new File(assetsDir, "en-us-ptm"))//設置聲學模型的文件夾
                .setDictionary(new File(assetsDir, "cmudict-en-us.dict"))//設置字典模型
                .setRawLogDir(assetsDir) // To disable logging of raw audio comment out this call (takes a lot of space on the device)

                .getRecognizer();
        recognizer.addListener(this);

        /** In your application you might not need to add all those searches.
         * They are added here for demonstration. You can leave just one.
         */

        // 創建短語監聽
        recognizer.addKeyphraseSearch(KWS_SEARCH, KEYPHRASE);

        //創建命令文件監聽
        File menuGrammar = new File(assetsDir, "menu.gram");
        recognizer.addGrammarSearch(MENU_SEARCH, menuGrammar);

        // Create grammar-based search for digit recognition
        File digitsGrammar = new File(assetsDir, "digits.gram");
        recognizer.addGrammarSearch(DIGITS_SEARCH, digitsGrammar);

        // Create language model search
        File languageModel = new File(assetsDir, "weather.dmp");
        recognizer.addNgramSearch(FORECAST_SEARCH, languageModel);

        // Phonetic search
        File phoneticModel = new File(assetsDir, "en-phone.dmp");
        recognizer.addAllphoneSearch(PHONE_SEARCH, phoneticModel);
    }

    private void switchSearch(String searchName) {
        recognizer.stop();

        // If we are not spotting, start listening with timeout (10000 ms or 10 seconds).
        if (searchName.equals(KWS_SEARCH))
            recognizer.startListening(searchName);
        else
            recognizer.startListening(searchName, 10000);
    }

這里需要注意設置聲學模型文件夾的時候不需要寫成 sync/ptm-zh,sync不需要寫,否則會報錯找不到文件。到這里按照 demo 的示例代碼基本可以學會重要的方法調用了,如開始監聽和結束監聽等。

這里再提一下我們創建命令文件監聽的時候需要使用的 .gram 文件,其實看一下 demo 中的 .gram 文件我們也知道該如何編寫自己的命令文件了

#JSGF V1.0;

grammar menu;

public <item> = 命令詞1 | 命令詞2 | 命令詞3;

一旦開始命令文件監聽,則監聽器就會監聽命令文件中的命令詞,當監聽到語音的時候就會取出發音最相似的那個命令詞返回到監聽結果。請注意,這里意思是取出發音最相近的,這導致的時候也許你並沒有說這些命令詞的任何一個,只是監聽器同樣會取出他認為最相近的一個返回給結果,也就是表現的識別過於敏感,我在使用過程中還是屬於可接受范圍內。可以根據自己需求選擇短語監聽或者命令文件監聽。

結束

到這里基本就可以使用 PocketSpinnx 離線語音識別了,一些細節的處理還需要自己閱讀 demo 中的代碼,代碼不多而且容易理解,可以加深對使用的理解,另外,推薦閱讀官方文檔,能夠詳細知道項目的運行原理,以及文中沒有提到的一些內容,雖然是英文的,但通過單詞翻譯也不難理解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM