您的位置:首页 > 编程语言 > C语言/C++

Kinect2.0 挥手动作的识别(C++实现)

2016-04-25 22:26 211 查看
最近刚入手一个Kinect 2.0,但是感觉学起来不容易,网上的资料并不多,搜了很多都是一代的资料,只能对着官方给的例子一个个的看,不懂得地方查函数库。在网上看到了一篇挥手动作识别的例子,觉得蛮有意思,但是,是针对一代的版本,在二代中跑不起来,特地改了一下,全当练练手。由于是新手,有不准确的地方,还请各位多指导。原文链接:点击这里
#include <Windows.h>
#include <Kinect.h>
#include <iostream>
#include<ctime>
#include<cassert>
#include<process.h>

#pragma comment(lib,"kinect20.lib")

using namespace std;

#define _DDDEBUG

static int CTRL = 0;

template<class Interface>
inline void SafeRelease(Interface *& pInterfaceToRelease)
{
if (pInterfaceToRelease != NULL){
pInterfaceToRelease->Release();
pInterfaceToRelease = NULL;
}
}

// 记录手势当前位置
enum GesturePos{ //
NonePos = 0,
Left,
Right,
Neutral
};

// 判断识别状态
enum DetectionState{
NoneState = 0,
Success,
Failed,
InProgress
};

// 判断手势需要的数据
struct DataState{
GesturePos Pos;     // 每个人的左右手
DetectionState State; // 状态
int times;
time_t timestamp;
void Reset() // 状态的重置
{
Pos = GesturePos::NonePos;
State = DetectionState::NoneState;
times = 0;
timestamp = 0;
}
};

// 完成手势判断逻辑功能
class GestureDetection{
public:
GestureDetection(float neutral_threshold, int times, double difftimes)
: neutral_threshold(neutral_threshold)
, times(times)
, difftimes(difftimes)
, left_hand(0)
, right_hand(1)
{
for (int i = 0; i < 1; i++)
{
wave_datas[i][left_hand].Reset();
wave_datas[i][right_hand].Reset();
}
}
// 功能:循环接收骨骼数据,如果识别出为挥手动作则输出:success,
// 识别失败输出:failed,
void Update(IBody * frame)
{

if (NULL == frame)
return;
for (int i = 0; i < 1; i++)
{
JudgeState(frame, wave_datas[i][right_hand],true);
}
}
private:
DataState wave_datas[1][2];        // 记录每个人,每只手的状态
const int left_hand;                            // 左手 ID
const int right_hand;                           // 右手 ID
// 中间位置阀值:在该范围内的都认为手在中间位置(相对于肘部的 x 坐标)
const float neutral_threshold;
// 挥手次数阀值,达到该次数认为是挥手
const int times;
// 时间限制,如果超过该时间差依然识别不出挥手动作则认为识别失败
const double difftimes;

// 判断当前的状态成功输出:success,并生成事件:DetectionEvent
// 失败输出 failed,供 UpDate 函数调用
void JudgeState(IBody *n_body, DataState& data,bool isLeft = true)
{

Joint joints[JointType_Count]; // 定义骨骼信息

n_body->GetJoints(JointType::JointType_Count, joints);  // 获取骨骼信息节点

int elbow = JointType_ElbowRight;

int hand = JointType_HandRight;

if (!IsSkeletonTrackedWell(n_body, isLeft))  //  如果手部的位置在肘部之上  则认为为真
{
if (data.State == InProgress)
{
#ifdef _DDEBUG
cout << "not a well skeleton, detection failed!\n";
#endif
data.Reset();
return;
}
}

float curpos = joints[hand].Position.X;
float center = joints[elbow].Position.X;  //  得到人手部和肘部的X坐标的位置  都是右手

if (!IsNeutral(curpos, center))  //  如果手部不是在中立的位置
{
if (data.Pos == NonePos)
{
#ifdef _DDEBUG
cout << "found!\n";
#endif

data.times++;

if ( get_length(curpos, center) == -1 )
{
data.Pos = Left;
}
else if (get_length(curpos, center) == 1)
{
data.Pos = Right;
}
cout << "times:" << data.times << endl;
if (data.Pos == Left)
{
cout << "left !\n";
}
else if (data.Pos == Right)
{
cout << "right!\n";
}
else
cout << "you can't see me!\n";

data.State = InProgress;
data.timestamp = time(NULL);

}

else if (  ( (data.Pos == Left) && get_length(curpos, center) == 1)  || ( (data.Pos == Right) && get_length(curpos, center) == -1  ) )  // 左摆找右摆  右摆找左摆
{

assert(data.State == InProgress);
data.times++;
data.Pos = (data.Pos == Left) ? Right : Left;
#ifdef _DDDEBUG
cout << "times:" << data.times << endl;
if (data.Pos == Left)
{
cout << "left !\n";
}
else if (data.Pos == Right)
{
cout << "right!\n";
}
else
cout << "you can't see me!\n";
#endif
if (data.times >= times)
{
#ifdef _DDDEBUG
cout << "success!\n";
#endif
CTRL = 1;
data.Reset();
}
else if (difftime(time(NULL), data.timestamp) > difftimes)
{
#ifdef _DDDEBUG
cout << "time out, detection failed!\n";
cout << "data.times : " << data.times << endl;
#endif
data.Reset();
}
}
}

}

bool IsLeftSide(float curpos, float center)
{
int i = 0;
i = get_length(curpos,center);
if (i == -1)
{
return true;
}
else
{
return false;
}
}
bool IsRightSide(float curpos, float center)
{
int i = 0;
i = get_length(curpos, center);
if (i == 1)
{
return true;
}
else
{
return false;
}
}
bool IsNeutral(float curpos, float center) // 参数分别为手部的位置和肘部的位置  判断是否是中立的状态
{
int i = 0;
i = get_length(curpos, center);
if (i == 0)
{
return true;  // 是中立的状态
}
else
{
return false;
}
}

int get_length(float shou,float zhou)   //  在这里定义  右边是 1 左边是 -1 中间是 0
{
if (shou >= 0 && zhou >= 0)
{
if ((shou - zhou) > neutral_threshold)
{
return 1; // 在右边
}
else if ((shou - zhou) < neutral_threshold || (zhou - shou) > -neutral_threshold)
{
return 0;  // 中立
}
else
{
return -1;   // 左边
}
}
else if (shou >= 0 && zhou <= 0)
{
if ((shou + (-zhou)) > neutral_threshold)
{
return 1; // 右边
}
else
{
return 0; // 中立
}
}
else if (shou <= 0 && zhou >= 0)
{
if ( ((-shou) + zhou) > neutral_threshold )
{
return -1; // 左边
}
else
{
return 0; // 中立
}
}
else
{
if ((-shou) >= (-zhou))
{
if (((-shou) + zhou) > neutral_threshold)
{
return -1; // 左边
}
else if (((-shou) + zhou) < neutral_threshold)
{
return 0; // 中立
}
else
{
return 1;  // 右边
}
}
else
{
if (((-zhou) + shou) > neutral_threshold )
{
return 1; // 右边
}
else
{
return 0; // 中立
}
}
}

}

// 判断骨骼追踪情况:包括骨骼追踪完好且手部位置在肘上面
bool IsSkeletonTrackedWell(IBody * n_body, bool isLeft = true)
{
Joint joints[JointType_Count];
n_body->GetJoints(JointType::JointType_Count, joints);

int elbow = JointType_ElbowRight;

int hand = JointType_HandRight;

if (joints[hand].Position.Y > joints[elbow].Position.Y)
{
return true;
}
else
{
return false;
}

}
};

int main()
{
IKinectSensor *kinect = NULL;
HRESULT hr = S_OK;
hr = GetDefaultKinectSensor(&kinect);  //  得到默认的设备

if (FAILED(hr) || kinect == NULL)
{
cout << "创建 sensor 失败\n";
return -1;
}
if (kinect->Open() != S_OK) // 是否打开成功
{
cout << "Kinect sensor 没准备好\n";
return -1;
}

IBodyFrameSource *bady = nullptr;  // 获取源
hr = kinect->get_BodyFrameSource(&bady);

IBodyFrameReader *pBodyReader;

hr = bady->OpenReader(&pBodyReader); // 打开获取骨骼信息的  Reader
if (FAILED(hr)){
std::cerr << "Error : IBodyFrameSource::OpenReader()" << std::endl;
return -1;
}

cout << "开始检测\n";

GestureDetection gesture_detection(0.05, 5, 5);

while (1)
{
IBodyFrame* pBodyFrame = nullptr;
hr = pBodyReader->AcquireLatestFrame(&pBodyFrame);

if (SUCCEEDED(hr)){
IBody* pBody[BODY_COUNT] = { 0 }; // 默认的是 6 个骨骼 ,初始化所有的骨骼信息
//更新骨骼数据
hr = pBodyFrame->GetAndRefreshBodyData(BODY_COUNT, pBody); // 刷新骨骼信息(6个)
if (SUCCEEDED(hr))
{
BOOLEAN bTracked = false;

for (int i = 0; i < 6; i++)
{
hr = pBody[i]->get_IsTracked(&bTracked); // 检查是否被追踪

if (SUCCEEDED(hr) && bTracked)
{

gesture_detection.Update(pBody[i]);
}
}
}
for (int count = 0; count < BODY_COUNT; count++){
SafeRelease(pBody[count]);
}
}
if (CTRL == 1)
{
break;  //  识别成功以后  跳出识别程序
}

SafeRelease(pBodyFrame);  // 别忘了释放
}

kinect->Close();  // 关闭设备
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: