谈谈NITE 2的姿势探测识别和手势探测识别

主要内容:

一、姿势探测识别

1.1 内容介绍  

  NITE 2的姿势探测识别功能和人体骨骼跟踪一样,是由UserTracker提供的,在NiTE 2.0版本中,提供了两种姿势:“POSE_PSI”(我称它为“投降姿势”)和“POSE_CROSS_HAND”(称之为“双手抱胸”),除此之外,我们没办法提供自己设定的特定姿势的探测和识别。

  在之前的版本中,由于“POSE_PSI”是用来做骨架跟踪校正的标志姿势使用的,但后来NITE提供了不用校正姿势的情况下就可以进行骨架跟踪了,所以在没有特殊使用的情况下,本人(谈谈NITE 2与OpenCV结合的第二个程序(提取人体骨骼坐标))觉得在骨骼跟踪上,姿势的探测已然成为了多余的了;但对于使用姿势识别有关方面的研究的,我想这个姿势探测识别应该还是重要的,没准在NITE后面的版本中提供”自制的特定姿势“跟踪识别了。

  由于在NITE中主要提供的是人体跟踪和手的跟踪,而人体姿势探测属于前者,所以姿势探测识别和人体骨骼跟踪一样,都是使用UserTracker。首先通过获得新的使用者信息;然后根据指定使用者,利用UserTracker开始进行姿势的探测;最后根据每次探测到最新的姿势资料,进行判定识别,以及开始我们自己需要的处理工作。

1.2 代码介绍

  同样的,直接上代码说明如何利用UserTracker进行姿势探测。

#include "stdafx.h"
#include <iostream>

// 载入NiTE头文件
#include <NiTE.h>

// using namespace
using namespace std;
using namespace nite;

int main( int argc, char** argv )
{
    // 初始化NiTE环境
    NiTE::initialize();

    // 创建UserTracker跟踪器
    UserTracker mUserTracker;
    mUserTracker.create();

    while(true)
    {
        // 读取帧信息
        UserTrackerFrameRef mUserFrame;
        mUserTracker.readFrame( &mUserFrame);

        // 通过帧信息,获得用户数据UserData
        const Array<UserData>& aUsers = mUserFrame.getUsers();

        for( int i = 0; i < aUsers.getSize(); ++ i )
        {
            const UserData& rUser = aUsers[i];
            const UserId& uID = rUser.getId();

            if( rUser.isNew() )
            {
                cout << "User " << uID << " found." << endl;

                // 为每一个新用户进行姿势探测
                cout << "Start pose detection " << uID<< endl;

                // 探测uID的两种姿势
                mUserTracker.startPoseDetection( uID, POSE_PSI );
                mUserTracker.startPoseDetection( uID, POSE_CROSSED_HANDS );
            }
            else if( rUser.isLost() )
            {
                cout << "User " << uID << " lost." << endl;
            }
            else
            {
                // 读取用户的“POSI_PSI”的姿势状态
                const PoseData& rPosePSI = rUser.getPose( POSE_PSI );

                // 当做了“POSI_PSI”时:
                if( rPosePSI.isEntered() )
                    cout << " 开始---投降姿势(PSI pose)" << endl;

                if( rPosePSI.isHeld() )
                    cout << " 保持---投降姿势(PSI pose)" << endl;

                // 当做完了“POSI_PSI”后,双手放下时:
                if( rPosePSI.isExited() )
                    cout << "停止---投降姿势(PSI pose)" << endl;

                // 同样的读取“POSE_CROSSED_HANDS”的姿势状态
                const PoseData& rPCH = rUser.getPose( POSE_CROSSED_HANDS );

                if( rPCH.isEntered() )
                    cout << " 开始---双手抱胸(Cross Hand pose)" << endl;

                if( rPCH.isHeld() )
                    cout << " 保持---双手抱胸(Cross Hand pose)" << endl;

                if( rPCH.isExited() )
                    cout << " 停止---双手抱胸(Cross Hand pose)" << endl;
            }
        }
    }

    // 关闭UserTracker跟踪
    mUserTracker.destroy();

    // 关闭NITE环境
    NiTE::shutdown();

    return 0;
}

上图:

  当开始姿势探测时,只要双手举起,PSI就会触发,使rPosePSI.isEntered()值为true;当保持着这个姿势一段时间,就会使rPosePSI.isHeld()值为true,表示目前的状态为保持着投降姿势;当双手放下时,rPosePSI.isExited()值为true,表示不再保持着投降姿势。同样的道理,当你做出”双手抱胸“的姿势(POSE_CROSSED_HANDS)时,也同样提供isEntered()、isHeld()和isExited()三个函数来表示当前探测的姿势的状态情况。

  注:当我无论如何做出”双手抱胸“的姿势(POSE_CROSSED_HANDS)时,都无法触发这一姿势的跟踪,所以我的结论是我还不知道怎么去”双手抱胸“~~~

1.3 总结

  对于姿势探测识别,主要包括以下几个步骤:

  • 初始化NiTE环境:NiTE::initialize();
  • 创建UserTracker跟踪器:UserTracker::create();
  • 读取跟踪器帧信息:UserTracker::readFrame( &UserTrackerFrameRef);
  • 通过帧信息,获得用户数据UserData:mUserFrame::getUsers();
  • 对特定用户开始姿势探测(包括”投降姿势“和”双手抱胸姿势“的探测):UserTracker::startPoseDetection(UserId user, PoseType type);
  • 读取用户的指定姿势的状态信息:PoseData& getPose(PoseType type);
  • 主要有isEntered()、isHeld()、isExited()三个函数来表示当前探测的姿势的状态情况;
  • 停止UserTracker跟踪器:UserTracker::destroy();
  • 最后停止NiTE环境:NiTE::shutdown();

二、手势探测识别

2.1 内容介绍

  在NITE中,手势探测识别主要是由HandTracker类提供的,和UserTracker一样,HandTracker还提供的手部位置的跟踪(谈谈NITE 2的第一个程序HandViewer谈谈NITE 2与OpenCV结合的第一个程序,以及谈谈NITE 2与OpenCV结合提取指尖坐标等处都做了介绍了)。根据目前的NITE提供的手势跟踪和之前的版本个人感觉差不多。首先都是不针对指定用户的手势识别(这点和姿势探测识别不一样),而是针对整个界面帧信息进行分析,找到符合的手势;其次探测识别的手势只有三个:”GESTURE_WAVE“(挥手)、”GESTURE_CLICK“(手掌前推在缩回来)和”GESTURE_HAND_RAISE“(手举起)。最后目前都没有提供自制的手势探测(这点和姿势探测一样)。

2.2 代码说明

#include "stdafx.h"
#include <iostream>

// 载入NiTE头文件
#include <NiTE.h>

// using namespace
using namespace std;
using namespace nite;

int main( int argc, char** argv )
{
    // 初始化NiTE环境
    NiTE::initialize();

    // 创建HandTracker跟踪器
    HandTracker mHandTracker;
    mHandTracker.create();

    // 设定手势探测(GESTURE_WAVE、GESTURE_CLICK和GESTURE_HAND_RAISE)
    mHandTracker.startGestureDetection( GESTURE_WAVE );
    mHandTracker.startGestureDetection( GESTURE_CLICK );
    mHandTracker.startGestureDetection( GESTURE_HAND_RAISE );

    while(true)
    {
        // 读取帧信息
        HandTrackerFrameRef mHandFrame;
        mHandTracker.readFrame( &mHandFrame );

        // 整个界面帧信息进行分析,找到符合的手势
        const Array<GestureData>& aGestures = mHandFrame.getGestures();

        for( int i = 0; i < aGestures.getSize(); ++ i )
        {
            const GestureData& rGesture = aGestures[i];

            // 对找到的手势进行类型判断,并输出类型
            cout << "Detect gesture ";
            switch( rGesture.getType() )
            {
            case GESTURE_WAVE:
                cout << "摇手手势---“wave”:";
                break;

            case GESTURE_CLICK:
                cout << "前推并收回手势---“click”";
                break;

            case GESTURE_HAND_RAISE:
                cout << "举起手势---“hand raise”";
                break;
            }

            // 得到的手势信息中还包含了当前手势的坐标位置
            const Point3f& rPos = rGesture.getCurrentPosition();
            cout << " 手势位置为: (" << rPos.x << ", " << rPos.y << ", " << rPos.z << ")" << endl;

            // 以及手势状态,完成状态和进行状态
            if( rGesture.isComplete() )
                cout << "  手势完成";
            if( rGesture.isInProgress() )
                cout << "  手势正在进行";

            cout << endl;
        }
    }

    // 关闭HandTracker跟踪
    mHandTracker.destroy();

    // 关闭NITE环境
    NiTE::shutdown();

    return 0;
}

上图:

  注:三个手势中”举起“手势太好识别了,直接掩盖了其它两个手势,所以在实际的手势识别中,我建议不用检测”举起“这个手势~~~。我把上面代码中mHandTracker.startGestureDetection( GESTURE_HAND_RAISE );给注释了,再看运行结果:

  注:排除了”举起“手势的捣乱之后,发现”前推并收回“手势(click),动作最好掌控,识别过程和效果也是最好(个人觉得);同时我怎么”摇手“(wave),好像都出不了检测结果,具体什么原因现在我也不知道(估计又是我手势做的不对),有知道的烦请教教我,谢谢~~~

2.3 总结

  具体手势探测识别流程和1.3的相似,看了上面的代码肯定知道,所以这里就不写了。最后我的建议是:如果要进行手势探测识别的话,我提议是探测”click“手势~~~

  写的粗糙~~~

  

posted @ 2013-01-25 12:19  叶梅树  阅读(4540)  评论(3编辑  收藏  举报