不说点废话,看代码是不是蒙圈了呢 😝
环境配置
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