Microsoft Speech 语音识别

废话不多说,直奔主题!

1.环境

??Microsoft Speech SDK 11 (语音识别SDK)点这里

2.语音识别

MKSpeech.h

#pragma once
#include <Windows.h>
#include <sapi.h>
#include <sphelper.h>
#include "stdafx.h"
class MKSpeech
{
private:
    /** 是否打开*/
    bool isOpen;
    /** 是否初始化完成*/
    bool isInit;
private:
    // 音频
    IAudioBeam*                 m_pAudioBeam ;
    // 语音识别输入流
    ISpStream*                  m_pSpeechStream ;
    // 语音识别器
    ISpRecognizer*              m_pSpeechRecognizer ;
    // 语音识别上下文
    ISpRecoContext*             m_pSpeechContext ;
    // 语音识别语法
    ISpRecoGrammar*             m_pSpeechGrammar ;
    // 语音识别触发事件
    HANDLE                      m_hSpeechEvent ;
    // 音频处理线程
    std::thread                 m_threadAudio;
    // 语法文件
    WCHAR*                      s_GrammarFileName;
private:
    // 初始化语音识别
    HRESULT init_speech_recognizer();
    // 音频线程
    static void AudioThread(MKSpeech* pointer);
    // 语音行为
    void speech_behavior(const SPPHRASEPROPERTY* tag);
    // 语音处理
    void speech_process();
public:
    MKSpeech(void);
    ~MKSpeech(void);
    void open(int type);
    void close(void);

private:
    /** 回掉的函数指针*/
    ErrorCallBack  _errorCallBack;
    AudioCallBack  _audioCallBack;
public:
    /**设置回掉函数*/
    void m_setErrorActionCallBack(ErrorCallBack call);
    void m_setAudioCallBack(AudioCallBack call);

    void m_errorCallBack(string codeStr);
    void m_audioCallBack(string str,AudioCallStatus status);
};

MKSpeech.cpp

#include "MKSpeech.h"
MKSpeech::MKSpeech(void)
{
    isOpen = false;
    isInit = false;
    s_GrammarFileName = L"Grammar.xml";
    m_pAudioBeam = nullptr;    
    m_pSpeechStream = nullptr;    
    m_pSpeechRecognizer = nullptr;   
    m_pSpeechContext = nullptr;    
    m_pSpeechGrammar = nullptr;    
    m_hSpeechEvent = nullptr;   
}


MKSpeech::~MKSpeech(void)
{

}

HRESULT MKSpeech::init_speech_recognizer()
{
    HRESULT hr = S_OK;
    // 创建语音输入流
    hr = CoCreateInstance(CLSID_SpStream, nullptr, CLSCTX_INPROC_SERVER, __uuidof(ISpStream), (void**)&m_pSpeechStream);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("CoCreateInstance CLSID_SpStream failed");
        return hr;
    }
    // 创建语言识别器
    hr = CoCreateInstance(CLSID_SpInprocRecognizer, nullptr, CLSCTX_INPROC_SERVER, __uuidof(ISpRecognizer), (void**)&m_pSpeechRecognizer);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("CoCreateInstance CLSID_SpInprocRecognizer failed");
        return hr;
    }
    //创建默认音频输入对象
    CComPtr<ISpObjectToken> ISPToken = nullptr;
    hr = SpGetDefaultTokenFromCategoryId(SPCAT_AUDIOIN,&ISPToken);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("SpGetDefaultTokenFromCategoryId failed");
        return hr;
    }
    //设置识别引擎输入源
    hr = m_pSpeechRecognizer->SetInput(ISPToken,TRUE);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("SetInput failed");
        return hr;
    }
    // 创建语音识别对象
    ISpObjectToken *pEngineToken = nullptr;
    hr = SpFindBestToken(SPCAT_RECOGNIZERS, L"language=804", nullptr, &pEngineToken);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("SpFindBestToken failed");
        return hr;
    }
    // 设置待识别语言
    m_pSpeechRecognizer->SetRecognizer(pEngineToken);
    // 创建语音识别上下文
    hr = m_pSpeechRecognizer->CreateRecoContext(&m_pSpeechContext);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("m_pSpeechRecognizer CreateRecoContext failed");
        return hr;
    }
    SafeRelease(pEngineToken);
    // 适应性 ON! 防止因长时间的处理而导致识别能力的退化
    hr = m_pSpeechRecognizer->SetPropertyNum(L"AdaptationOn", 0);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("m_pSpeechRecognizer SetPropertyNum failed");
        return hr;
    }
    // 创建语法
    hr = m_pSpeechContext->CreateGrammar(1, &m_pSpeechGrammar);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("m_pSpeechContext CreateGrammar failed");
        return hr;
    }
    //加载语法规则
    hr = m_pSpeechGrammar->LoadCmdFromFile(s_GrammarFileName, SPLO_DYNAMIC);
    if (!SUCCEEDED(hr)){
        hr = m_pSpeechGrammar->LoadCmdFromFile(L".\\resources\\app\\kinectLib\\Grammar.xml", SPLO_DYNAMIC);     
    }
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("m_pSpeechGrammar LoadCmdFromFile failed");
        return hr;
    }
    // 激活语法规则
    hr = m_pSpeechGrammar->SetRuleState(nullptr, nullptr, SPRS_ACTIVE);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("m_pSpeechGrammar SetRuleState failed");
        return hr;
    }
    // 设置识别器一直读取数据
    hr = m_pSpeechRecognizer->SetRecoState(SPRST_ACTIVE);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("m_pSpeechRecognizer SetRecoState failed");
        return hr;
    }
    // 设置对识别事件感兴趣
    hr = m_pSpeechContext->SetInterest(SPFEI(SPEI_RECOGNITION), SPFEI(SPEI_RECOGNITION));
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("m_pSpeechContext SetInterest failed");
        return hr;
    }
    // 保证语音识别处于激活状态
    m_pSpeechContext->Resume(0);
    // 获取识别事件
    m_hSpeechEvent = m_pSpeechContext->GetNotifyEventHandle();
    
    return hr;
}

// 音频线程
void MKSpeech::AudioThread(MKSpeech* pointer){
    // 先设置
    HANDLE events[] = { pointer->m_hSpeechEvent };
    bool exit = false;
    while (!exit) {
        switch (::WaitForMultipleObjects(lengthof(events), events, FALSE, 8000)){
        case WAIT_OBJECT_0:
            // 语言识别
            pointer->speech_process();
            exit = true;
            pointer->close();
            break;
        case WAIT_TIMEOUT:
            pointer->m_audioCallBack("faild",AudioCallStatus_Faild);
            exit = true;
            pointer->close();
            break;
        }
    }
}


// 音频处理
void MKSpeech::speech_process() {
    
    // 置信阈值
    const float ConfidenceThreshold = 0.3f;

    SPEVENT curEvent = { SPEI_UNDEFINED, SPET_LPARAM_IS_UNDEFINED, 0, 0, 0, 0 };
    ULONG fetched = 0;
    HRESULT hr = S_OK;
    // 获取事件
    m_pSpeechContext->GetEvents(1, &curEvent, &fetched);
    while (fetched > 0)
    {
        // 确定是识别事件
        switch (curEvent.eEventId)
        {
        case SPEI_RECOGNITION:
            // 保证位对象
            if (SPET_LPARAM_IS_OBJECT == curEvent.elParamType) {
                ISpRecoResult* result = reinterpret_cast<ISpRecoResult*>(curEvent.lParam);
                SPPHRASE* pPhrase = nullptr;
                // 获取识别短语
                hr = result->GetPhrase(&pPhrase);
                if (SUCCEEDED(hr)) {
                    // DEBUG时显示识别字符串
                    WCHAR* pwszFirstWord;
                    result->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, TRUE, &pwszFirstWord, nullptr);
                    //_cwprintf(pwszFirstWord);
                    char * m_char;    
                    int len= WideCharToMultiByte( CP_ACP ,0,pwszFirstWord ,wcslen( pwszFirstWord ), NULL,0, NULL ,NULL);    
                    m_char = new char[len+1];     
                    WideCharToMultiByte( CP_ACP ,0,pwszFirstWord,wcslen( pwszFirstWord ),m_char,len, NULL ,NULL );     
                    m_char[len]= '\0';     
                    printf(m_char);

                    //string base64Str =  GbkToUtf8(m_char);

                    
                    ::CoTaskMemFree(pwszFirstWord);

                    pPhrase->pProperties;
                    const SPPHRASEELEMENT* pointer = pPhrase->pElements;
                    if ((pPhrase->pProperties != nullptr) && (pPhrase->pProperties->pFirstChild != nullptr)) {
                        const SPPHRASEPROPERTY* pSemanticTag = pPhrase->pProperties->pFirstChild;
                        
                        //CString str(lpcwStr);
                        _cwprintf(pSemanticTag->pszValue);

                        char * m_char2;    
                        int len2= WideCharToMultiByte( CP_ACP ,0,pSemanticTag->pszValue ,wcslen( pSemanticTag->pszValue ), NULL,0, NULL ,NULL);
                    m_char2 = new char[len2+1];     
                    WideCharToMultiByte( CP_ACP ,0,pSemanticTag->pszValue,wcslen( pSemanticTag->pszValue ),m_char2,len2, NULL ,NULL );     
                    m_char2[len2]= '\0';     
                    printf(m_char2);


                        m_audioCallBack(m_char2,AudioCallStatus_Success);
//#ifdef _DEBUG         
                        _cwprintf(L"   置信度:%d%%\n", (int)(pSemanticTag->SREngineConfidence*100.f));
//#endif
                        if (pSemanticTag->SREngineConfidence > ConfidenceThreshold) {
                            speech_behavior(pSemanticTag);
                        }
                    }
                    ::CoTaskMemFree(pPhrase);
                }
            }
            break;
        }

        m_pSpeechContext->GetEvents(1, &curEvent, &fetched);
    }

    return;
}

// 语音行为
void MKSpeech::speech_behavior(const SPPHRASEPROPERTY* tag){
    if (!tag) return;
    if (!wcscmp(tag->pszName, L"战况")){
        enum class Subject{
            US = 0,
            Enemy
        } ;
        enum class Predicate{
            Destroy = 0,
            Defeat,
            Breakdown
        };
        // 分析战况
        union  Situation{
            struct{
                // 主语
                Subject subject;
                // 谓语
                Predicate predicate;
                // 对象
                int object2;
                // 宾语
                int object;

            };
            UINT32 data[4];
        };
        Situation situation;
        auto obj = tag->pFirstChild;
        auto pointer = situation.data;
        // 填写数据
        while (obj) {
            *pointer = obj->vValue.lVal;
            ++pointer;
            obj = obj->pNextSibling;
        }
        // XXX
    }
    else if (!wcscmp(tag->pszName, L"发现东西")){
        // 发现东西
    }
}

void MKSpeech::m_setErrorActionCallBack(ErrorCallBack call)
{
    _errorCallBack = call;
}

void MKSpeech::m_setAudioCallBack(AudioCallBack call)
{
    _audioCallBack = call;
}

void MKSpeech::m_errorCallBack(string codeStr) 
{
    if (_errorCallBack)
    {
        _errorCallBack(codeStr);
    }
}

void MKSpeech::m_audioCallBack(string str,AudioCallStatus status)
{
    if (isOpen)
    {
        if (_audioCallBack)
        {
            _audioCallBack(str,status);
        }
    }
    
}

void MKSpeech::open(int type)
{
    if (!isInit)
    {
        HRESULT hr = init_speech_recognizer();
        if (SUCCEEDED(hr))
        {
            isInit = true;
        }
    }
    if (isInit)
    {
        if (type == 0)
        {
            printf("%d",wcscmp(s_GrammarFileName,L"Grammar.xml"));
            if (wcscmp(s_GrammarFileName,L"Grammar.xml") != 0)
            {
                s_GrammarFileName = L"Grammar.xml";
                //加载语法规则
                HRESULT hr = m_pSpeechGrammar->LoadCmdFromFile(s_GrammarFileName, SPLO_DYNAMIC);
                if (!SUCCEEDED(hr)){
                    hr = m_pSpeechGrammar->LoadCmdFromFile(L".\\resources\\app\\kinectLib\\Grammar.xml", SPLO_DYNAMIC); 
                }
                if (!SUCCEEDED(hr))
                {
                    m_errorCallBack("m_pSpeechGrammar LoadCmdFromFile failed");
                    return ;
                }
                // 激活语法规则
                hr = m_pSpeechGrammar->SetRuleState(nullptr, nullptr, SPRS_ACTIVE);
                if (!SUCCEEDED(hr))
                {
                    m_errorCallBack("m_pSpeechGrammar SetRuleState failed");
                    return ;
                }
            }
        }else
        {
            printf("%d",wcscmp(s_GrammarFileName,L"Grammar_en.xml"));
            if (wcscmp(s_GrammarFileName,L"Grammar_en.xml") != 0)
            {
                s_GrammarFileName = L"Grammar_en.xml";
                //加载语法规则
                HRESULT hr = m_pSpeechGrammar->LoadCmdFromFile(s_GrammarFileName, SPLO_DYNAMIC);
                if (!SUCCEEDED(hr)){
                    hr = m_pSpeechGrammar->LoadCmdFromFile(L".\\resources\\app\\kinectLib\\Grammar_en.xml", SPLO_DYNAMIC);      
                }
                if (!SUCCEEDED(hr))
                {
                    m_errorCallBack("m_pSpeechGrammar LoadCmdFromFile failed");
                    return ;
                }
                // 激活语法规则
                hr = m_pSpeechGrammar->SetRuleState(nullptr, nullptr, SPRS_ACTIVE);
                if (!SUCCEEDED(hr))
                {
                    m_errorCallBack("m_pSpeechGrammar SetRuleState failed");
                    return ;
                }
            }
            
        }
        isOpen = true;
        m_pSpeechContext->SetContextState(SPCS_ENABLED);
        m_pSpeechContext->Resume( 0 );
        m_pSpeechRecognizer->SetRecoState(SPRST_ACTIVE) ;
        m_threadAudio.std::thread::thread(AudioThread, this);
    }
}

void MKSpeech::close(void)
{
    // Set Audio Input Strem to Stop
    ResetEvent(m_hSpeechEvent);
    m_pSpeechContext->SetContextState(SPCS_DISABLED);
    m_pSpeechRecognizer->SetRecoState(SPRST_INACTIVE_WITH_PURGE) ;
    m_pSpeechContext->Pause( 0 );
    isOpen = false;
}

KinectAudioStreamWrapper.h

#pragma once
#include "stdafx.h"

// Kinect 音频流简单封装
class KinectAudioStreamWrapper : public IStream{
public:
    // 构造函数
    KinectAudioStreamWrapper(IStream *p32BitAudioStream);
    // 析构函数
    ~KinectAudioStreamWrapper();
    // 删除默认构造
    KinectAudioStreamWrapper();
    // 这是语音状态
    void SetSpeechState(BOOL state){ m_SpeechActive = state; }
    // IUnknown 方法 实现
    STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_cRef); }
    STDMETHODIMP_(ULONG) Release() {
        UINT ref = InterlockedDecrement(&m_cRef);
        if (ref == 0){
            delete this;
        }
        return ref;
    }
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {
        if (riid == IID_IUnknown) {
            AddRef();
            *ppv = (IUnknown*)this;
            return S_OK;
        }
        else if (riid == IID_IStream) {
            AddRef();
            *ppv = (IStream*)this;
            return S_OK;
        }
        else {
            return E_NOINTERFACE;
        }
    }
    // IStream 方法
    STDMETHODIMP Read(void *, ULONG, ULONG *);
    STDMETHODIMP Write(const void *, ULONG, ULONG *);
    STDMETHODIMP Seek(LARGE_INTEGER, DWORD, ULARGE_INTEGER *);
    STDMETHODIMP SetSize(ULARGE_INTEGER);
    STDMETHODIMP CopyTo(IStream *, ULARGE_INTEGER, ULARGE_INTEGER *, ULARGE_INTEGER *);
    STDMETHODIMP Commit(DWORD);
    STDMETHODIMP Revert();
    STDMETHODIMP LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD);
    STDMETHODIMP UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD);
    STDMETHODIMP Stat(STATSTG *, DWORD);
    STDMETHODIMP Clone(IStream **);
private:
    // 引用计数
    UINT                    m_cRef;
    // 浮点缓冲区
    float*                  m_pFloatBuffer;
    // 缓冲区大小
    UINT                    m_uFloatBuferSize;
    // 封装对象
    IStream*                m_p32BitAudio;
    // 语音状态 使用BOOL保证数据对齐
    BOOL                    m_SpeechActive;
};
#include "KinectAudioStreamWrapper.h"

// KinectAudioStreamWrapper 构造函数
KinectAudioStreamWrapper::KinectAudioStreamWrapper(IStream *p32BitAudio) :m_p32BitAudio(p32BitAudio){
    m_cRef = 1;
    m_pFloatBuffer = nullptr;
    m_uFloatBuferSize = 0;
    m_SpeechActive = false;
    // 增加计数
    if (m_p32BitAudio){
        m_p32BitAudio->AddRef();
    }
}


// 析构函数
KinectAudioStreamWrapper::~KinectAudioStreamWrapper(){
    SafeRelease(m_p32BitAudio);
    if (m_pFloatBuffer){
        delete[] m_pFloatBuffer;
        m_pFloatBuffer = nullptr;
    }
}




// IStream Read方法的实现
STDMETHODIMP KinectAudioStreamWrapper::Read(void *pBuffer, ULONG cbBuffer, ULONG *pcbRead){
    // 参数检查
    if (!pBuffer || !pcbRead) return E_INVALIDARG;
    // 在读取前未使用 m_SpeechActive 返回S_OK
    if (!m_SpeechActive){
        *pcbRead = cbBuffer;
        return S_OK;
    }
    HRESULT hr = S_OK;
    // 目标是将浮点编码转换成16位PCM编码
    INT16* const p16Buffer = reinterpret_cast<INT16*>(pBuffer);
    // 长度倍数
    const int multiple = sizeof(float) / sizeof(INT16);
    // 检查缓冲区释放足够
    auto float_buffer_size = cbBuffer / multiple;
    if (float_buffer_size > m_uFloatBuferSize){
        // 不够就重新申请内存
        m_uFloatBuferSize = float_buffer_size;
        if (m_pFloatBuffer) delete[]m_pFloatBuffer;
        m_pFloatBuffer = new float[m_uFloatBuferSize];
    }
    // 缓冲区写入进度 字节为单位
    BYTE* pWriteProgress = reinterpret_cast<BYTE*>(m_pFloatBuffer);
    // 目前读取量
    ULONG bytesRead = 0;
    // 需要读取量
    ULONG bytesNeed = cbBuffer * multiple;
    // 循环读取
    while (true){
        // 已经不需要语音的情况下
        if (!m_SpeechActive){
            *pcbRead = cbBuffer;
            hr = S_OK;
            break;
        }
        // 从包装对象获取数据
        hr = m_p32BitAudio->Read(pWriteProgress, bytesNeed, &bytesRead);

        //printf("读取字节数: %d", &bytesRead);

        bytesNeed -= bytesRead;
        pWriteProgress += bytesRead;
        // 检查是否足够
        if (!bytesNeed){
            *pcbRead = cbBuffer;
            break;
        }
        // 不然就睡一个时间片的时间
        Sleep(20);
    }
    // 数据处理 float -> 16bit PCM
    if (!bytesNeed){
        for (UINT i = 0; i < cbBuffer / multiple; i++) {
            float sample = m_pFloatBuffer[i];
            // 区间保证
            //sample = max(min(sample, 1.f), -1.f);
            if (sample > 1.f) sample = 1.f;
            if (sample < -1.f) sample = -1.f;
            // 数据转换
            float sampleScaled = sample * (float)SHRT_MAX;
            p16Buffer[i] = (sampleScaled > 0.f) ? (INT16)(sampleScaled + 0.5f) : (INT16)(sampleScaled - 0.5f);
        }
    }
    return hr;
}

// 其他不需要支持的方法实现

STDMETHODIMP KinectAudioStreamWrapper::Write(const void *, ULONG, ULONG *)
{
    return E_NOTIMPL;
}

STDMETHODIMP KinectAudioStreamWrapper::Seek(LARGE_INTEGER /* dlibMove */, DWORD /* dwOrigin */, ULARGE_INTEGER * /* plibNewPosition */)
{
    // Seek在语音识别中是个比较关键的函数 Kinect目前不支持 但是防止失败返回S_OK
    return S_OK;
}

STDMETHODIMP KinectAudioStreamWrapper::SetSize(ULARGE_INTEGER)
{
    return E_NOTIMPL;
}

STDMETHODIMP KinectAudioStreamWrapper::CopyTo(IStream *, ULARGE_INTEGER, ULARGE_INTEGER *, ULARGE_INTEGER *)
{
    return E_NOTIMPL;
}

STDMETHODIMP KinectAudioStreamWrapper::Commit(DWORD)
{
    return E_NOTIMPL;
}

STDMETHODIMP KinectAudioStreamWrapper::Revert()
{
    return E_NOTIMPL;
}

STDMETHODIMP KinectAudioStreamWrapper::LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD)
{
    return E_NOTIMPL;
}

STDMETHODIMP KinectAudioStreamWrapper::UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD)
{
    return E_NOTIMPL;
}

STDMETHODIMP KinectAudioStreamWrapper::Stat(STATSTG *, DWORD)
{
    return E_NOTIMPL;
}

STDMETHODIMP KinectAudioStreamWrapper::Clone(IStream **)
{
    return E_NOTIMPL;
}

3.测试代码

main.h

#include "KinectApp.h"
#include <string>
#include "MKSpeech.h"

void __stdcall onActionCallBack(BodyRect bRect)
{
    printf("Person %d : X:%d Y:%d Z:%d State:%d \n", 0, bRect.X,bRect.Y,bRect.Z,bRect.type); 
}

void __stdcall onErrorCallBack(string codeStr)
{
    std::cout << codeStr << std::endl;
}

void __stdcall onPanActionCallBack(PanActionType type)
{
    printf("%c",type); 
}


void __stdcall onAudioCallBack(string str,AudioCallStatus status)
{

    printf("%d ",status); 
    
    std::cout << str << std::endl;
}

KinectApp *app;
MKSpeech *speech;

int main()
{
    
    if (SUCCEEDED(CoInitialize(NULL)))
    {
        /*app = new KinectApp();
        app->m_setActionCallBack(onActionCallBack);
        app->m_setErrorActionCallBack(onErrorCallBack);
        app->m_setPanActionCallBack(onPanActionCallBack);
        app->open();*/

        speech = new MKSpeech();
        speech->m_setErrorActionCallBack(onErrorCallBack);
        speech->m_setAudioCallBack(onAudioCallBack);
        while (true)
        {
            int a = rand()%2;
            printf("%d",a);
            speech->open(a);
            system("pause");
        }
    }
    
}

4.语音文件格式

<grammar root="rootRule" tag-format="semantics/1.0-literals" version="1.0" xml:lang="zh-CN" xmlns="http://www.w3.org/2001/06/grammar">
  <rule id="rootRule">
    <one-of>
      <item>
        <tag>5qyn5rSy</tag>
        <one-of>
          <item>青海交通职业技术学院</item>
          <item>欧洲</item>
          <item>亚洲</item>
          <item>青海</item>
          <item>黑龙江</item>
        </one-of>
      </item>
    </one-of>
  </rule>
</grammar>

5.几项注意

    1.语音识别可识别Kinect2Sdk语音输入流,语音识别对环境要求高(静),距离要近(2米内),越静识别速度、识别准确率越高。
    2.语音识别为指令性语音识别,识别指令相似度越高,识别准确率越低。
    3.本代码开发工具为Visual Studio 与上一篇手势控制鼠标为一套代码。
    4.如有问题、建议可联系249086205@qq.com。

本文参考文献:

    [https://blog.csdn.net/dustpg/column/info/k4w2dn](https://blog.csdn.net/dustpg/column/info/k4w2dn)

代码地址:链接: https://pan.baidu.com/s/1aY8S2VWOBIsW-JbAqcdEow 提取码: kujw

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容

  • 几个常见的语音交互平台的简介和比较 2018年07月12日 11:38:19青龙战阅读数:577 1.概述 最近做...
    Amy_GAOGAO阅读 765评论 0 3
  • 之前做的项目中有语音识别的需求, 是用讯飞语音SDK实现的。 有很多服务商提供声音转文字的服务,有收费的有免费。2...
    JoliLove阅读 3,670评论 1 3
  • 整合了语音识别的Python 程序提供了其他技术无法比拟的交互性和可访问性。最重要的是,在 Python 程序中实...
    凤羽化秋阅读 669评论 0 2
  • 【导读】亚马逊的 Alexa 的巨大成功已经证明:在不远的将来,实现一定程度上的语音支持将成为日常科技的基本要求。...
    派派森森阅读 1,037评论 2 9
  • 因为我们无法预料未来, 所以才会产生迷茫和恐惧。 因为我们无法预料未来, 所以才会收获惊喜与期待。
    凡声尘语阅读 196评论 1 2