识别手势语音重点

不说点废话,看代码是不是蒙圈了呢 😝

环境配置

  Kinect2 SDK直接安装,安装完成后会在系统环境变量中加入变量值 KINECTSDK20_DIR,语音文件安装需要安装多个文件,其中包括 runtime(speech SDK 的运行环境)、speech SDK、语言文件,要先安装运行环境在安装SDK,接下来安装需要的语言包

Kinect for Windows SDK 2.0
Microsoft Speech Platform - Software Development Kit (SDK) (Version 11)

kinect SDK

初始化SDK 并打开

IKinectSensor* m_pKinect ;
GetDefaultKinectSensor(&m_pKinect);
m_pKinect->Open();

读取身体数据

inline HRESULT KinectApp::initBodySource()
{
    //添加身体数据源
    IBodyFrameSource* bodySource = nullptr;
    HRESULT hr = m_pKinect->get_BodyFrameSource(&bodySource);
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("get_BodyFrameSource failed");
        return hr;
    }
    //读取身体数据源
    INT32 nBodyNum = 0;
    bodySource->get_BodyCount(&nBodyNum);
    hr = bodySource->OpenReader(&bodyReader); // 准备读取body数据
    if (!SUCCEEDED(hr))
    {
        m_errorCallBack("OpenReader failed");
        return hr;
    }
    return hr;
}

获取身体数据

inline void KinectApp::getBody(void){

    Sleep(sleeptime);
    // 获取最近的一帧数据
    IBodyFrame* bodyf = nullptr;
    bodyReader->AcquireLatestFrame(&bodyf);
    if (!bodyf)
    {
        return;
    }
    // 更新所有人身体数据
    IBody* ppBodies[BODY_COUNT] = { 0 };
    bodyf->GetAndRefreshBodyData(BODY_COUNT, ppBodies);

    IBody*pbody = getTrackedBody(ppBodies);
    if (pbody != nullptr)
    {
        getTrackedBodyJoints(pbody);
    }

    SafeRelease(bodyf);
}

每次获取到身体都为6个人的数组,因为是单人控制鼠标,获取到任务的id是无先后顺序的,所以获取到任务之后要进行锁定,下次获取是先判断当前锁定人物还在不,如果在直接获取手势,如果不在则锁定当前第一人

inline IBody* KinectApp::getTrackedBody(IBody* ppBodies[])

获取手势

HandState rightHandState = HandState_Unknown;
pBody->get_HandRightState(&rightHandState);

判断是不是在范围内,因为设备可获取范围为4米这里规定为2.8米内

inline bool KinectApp::isInScope(IBody* pBody)

获取手势坐标

Joint joints[JointType_Count];
HRESULT hr = pBody->GetJoints(_countof(joints), joints);
Joint rightJoint = joints[JointTypeArray[i]];
rightJoint.Position.X;
rightJoint.Position.Y;
rightJoint.Position.Z;

记录历史6个点的位置,用于求每次的位置的平均值,在误差值范围内更准确,显然鼠标的移动显得没有直接取当前那么流畅,还可以接受,不卡顿

inline BodyRect KinectApp::getHandRect(Joint joints[],JointType JointTypeArray[])

数据回调

void KinectApp::m_setActionCallBack(ActionCallBack call)
void KinectApp::m_setErrorActionCallBack(ErrorCallBack call)
void KinectApp::m_setPanActionCallBack(PanActionCallBack call)
void KinectApp::m_actionCallBack(int x,int y,int z,ActionType type)

滑动手势,实现难,操作起来更难,起始点难以确定,最后放弃

void KinectApp::m_panActionCallBack()

Speech SDK

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;
}

音频处理线程,语音识别是异步的,这里用了WaitForMultipleObjects 查看信号量是否改变, 在异步线程中执行该方法

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()

音频文件格式介绍
item tag 这里采用了base64字符串 5qyn5rSy,亚洲、青海、黑龙江、欧洲 等语音识别到都返回 5qyn5rSy 作为识别到的字符

<item>
<tag>5qyn5rSy</tag>
<one-of>
<item>河南大写</item>
<item>欧洲</item>
<item>亚洲</item>
<item>青海</item>
<item>黑龙江</item>
</one-of>
</item>

<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>
      <item>
        <tag>5qyn5rSy</tag>
        <one-of>
          <item>河南大写</item>
          <item>欧洲</item>
          <item>亚洲</item>
          <item>青海</item>
          <item>黑龙江</item>
        </one-of>
      </item>
    </one-of>
  </rule>
</grammar>

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

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

推荐阅读更多精彩内容