• 谈谈NITE 2与OpenCV结合的第一个程序


        开始之前,让我们自己开始再熟练熟练NITE 2的基本使用,主要包括以下几个步骤:

        1. 初始化NITE环境: nite::NiTE::initialize();

        2. 创建User跟踪器: nite::UserTracker mUserTracker; mUserTracker.create();

        3. 创建并读取User Frame信息:nite::UserTrackerFrameRef mUserFrame; mUserTracker.readFrame( &mUserFrame );

        4. 从User Frame信息中获取User信息:  const nite::Array<nite::UserData>& aUsers = mUserFrame.getUsers();然后根据User信息开始手势识别或者人体骨骼跟踪识别等我们自己需要的处理,开始我们自己的开发之旅。

        5. 释放Frame信息:mUserFrame.release();

        6. 关闭跟踪器:mUserTracker.destroy();

        7. 最后关闭NITE环境:nite::NiTE::shutdown();

        在这个是用NITE 2的整个过程中,我们没用是用到OpenNI的任何头文件和函数,使得程序看起来比较直观,不容易和OpenNI混淆使用。但是我们还是需要配置OpenNI 2,因为NITE 2是在OpenNI的基础上封装而来的;同时需要OpenNI 2和NITE 2两个函数库的Redist文件夹,我的做法是将这两个文件复制合并成新的Redist文件夹,然后将这个新的文件夹放在指定的任意路径下,最后在vs2010中将工作路径(Working Directory)指定到这个新的Redist文件夹路径上。

    具体代码如下(环境配置在这里省去):

    // YeNite2SimpleUsingOpenCV.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <iostream>
    
    // 载入NiTE.h头文件
    #include <NiTE.h>
    
    // using namespace
    using namespace std;
    
    int main( int argc, char** argv )
    {
        // 初始化NITE
        nite::NiTE::initialize();
    
        // 创建User跟踪器
        nite::UserTracker mUserTracker;
        mUserTracker.create();
    
        nite::UserTrackerFrameRef mUserFrame;
        for( int i = 0; i < 1000; ++ i )
        {
            // 读取User Frame信息
            mUserTracker.readFrame( &mUserFrame );
    
            // 从User Frame信息中获取User信息
            const nite::Array<nite::UserData>& aUsers = mUserFrame.getUsers();
    
            // Frame中User的个数
            for( int i = 0; i < aUsers.getSize(); ++ i )
            {
                const nite::UserData& rUser = aUsers[i];
    
                // 当有User用户出现在Kinect面前,则判断并显示
                if( rUser.isNew() )
                    cout << "New User [" << rUser.getId() << "] found." << endl;
            }
        }
    
        // 释放
    mUserFrame.release();

    // 关闭跟踪器 mUserTracker.destroy(); // 关闭NITE环境 nite::NiTE::shutdown(); return 0; }

        在这程序基础上,我们添加“手势识别”:具体说明直接见程序(具体说明可以参考之前的博文谈谈NITE 2的第一个程序HandViewer):

    // YeNite2SimpleUsingOpenCV.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <iostream>
    
    // 载入NiTE.h头文件
    #include <NiTE.h>
    
    // using namespace
    using namespace std;
    
    int main( int argc, char** argv )
    {
        // 初始化NITE
        nite::NiTE::initialize();
    
        // 创建Hand跟踪器
        nite::HandTracker* mHandTracker = new nite::HandTracker;
        mHandTracker->create();
    
        // 开始手势探测
        mHandTracker->startGestureDetection(nite::GESTURE_CLICK);
        mHandTracker->startGestureDetection(nite::GESTURE_WAVE);
        mHandTracker->startGestureDetection(nite::GESTURE_HAND_RAISE);
        
        nite::HandTrackerFrameRef mHandFrame;
        while(true)
        {
            // 读取Frame信息
            nite::Status rc = mHandTracker->readFrame(&mHandFrame);
            if (rc != nite::STATUS_OK)
            {
                cout << "GetNextData failed" << endl;
                return 0;
            }
    
            // 获取定位的手的快照信息,读取此时一共有多少个手势
            const nite::Array<nite::GestureData>& gestures = mHandFrame.getGestures();
            for (int i = 0; i < gestures.getSize(); ++i)
            {
                // 当获取的手势是正确完成了
                if (gestures[i].isComplete())
                {
                    // 就开始定位此时手势的坐标
                    const nite::Point3f& position = gestures[i].getCurrentPosition();
                    cout << "Gesture " << gestures[i].getType() << " at" << position.x << "," << position.y <<"," << position.z;
    
    
                    // nite::HandId newId ===>typedef short int HandId;
                    nite::HandId newId;
                    // 开始跟踪该有效手势的手心坐标,并确定该手的Id。
                    // 函数原型为:NITE_API NiteStatus niteStartHandTracking(NiteHandTrackerHandle, const NitePoint3f*, NiteHandId* pNewHandId);
                    mHandTracker->startHandTracking(gestures[i].getCurrentPosition(), &newId);
                }
            }
    
            // 获取定位手。
            const nite::Array<nite::HandData>& hands= mHandFrame.getHands();
            for (int i = 0; i < hands.getSize(); ++i)
            {
                const nite::HandData& user = hands[i];
    
                if (!user.isTracking())
                {
                    cout << "Lost hand %d\n" << user.getId();
                    nite::HandId id = user.getId();
                }
                else
                {
                    if (user.isNew())
                    {
                        cout << "Found hand %d\n" << user.getId();
                    }
                    else
                    {
                        cout << "Hand ID:" << hands[i].getId()
                            <<hands[i].getPosition().x << "," 
                            << hands[i].getPosition().y << ","
                            << hands[i].getPosition().z << endl;
                    }
                }
            }
        }
    
        mHandFrame.release();
        // 关闭跟踪器
        mHandTracker->destroy();
    
        // 关闭NITE环境
        nite::NiTE::shutdown();
    
        return 0;
    }

    程序执行结果如下:

        但是我们知道,单单有Hand的坐标还够,我们需要定位在具体的图像位置,利用手的坐标,来分割出手的轮廓等我们需要的信息,所以就要借助于OpenCV等常用工具库,现在开始看看如何结合OpenCV和HandTracker,直接上代码:

    // YeNite2SimpleUsingOpenCV.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <iostream>
    
    // 载入NiTE.h头文件
    #include <NiTE.h>
    
    // 载入OpenCV头文件
    #include "opencv2/opencv.hpp"
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    using namespace std;
    using namespace cv;
    
    int main( int argc, char** argv )
    {
    
        // 初始化NITE
        nite::NiTE::initialize();
    
        // 创建Hand跟踪器
        nite::HandTracker* mHandTracker = new nite::HandTracker;
        mHandTracker->create();
    
        // 创建OpenCV图像窗口
        namedWindow( "Hand Image",  CV_WINDOW_AUTOSIZE );
    
        // 循环读取数据流信息并保存在HandFrameRef中
        nite::HandTrackerFrameRef mHandFrame;
    
        // 开始手势探测
        mHandTracker->startGestureDetection(nite::GESTURE_CLICK);
        mHandTracker->startGestureDetection(nite::GESTURE_WAVE);
        mHandTracker->startGestureDetection(nite::GESTURE_HAND_RAISE);
    
        while( true )
        {
            // 读取Frame信息
            nite::Status rc = mHandTracker->readFrame(&mHandFrame);
            if (rc != nite::STATUS_OK)
            {
                cout << "GetNextData failed" << endl;
                return 0;
            }
    
            // 获取定位的手的快照信息,读取此时一共有多少个手势
            const nite::Array<nite::GestureData>& gestures = mHandFrame.getGestures();
            for (int i = 0; i < gestures.getSize(); ++i)
            {
                // 当获取的手势是正确完成了
                if (gestures[i].isComplete())
                {
                    // 就开始定位此时手势的坐标
                    const nite::Point3f& position = gestures[i].getCurrentPosition();
                    cout << "Gesture " << gestures[i].getType() << " at" << position.x << "," << position.y <<"," << position.z;
    
                    // nite::HandId newId ===>typedef short int HandId;
                    nite::HandId newId;
                    // 开始跟踪该有效手势的手心坐标,并确定该手的Id。
                    // 函数原型为:NITE_API NiteStatus niteStartHandTracking(NiteHandTrackerHandle, const NitePoint3f*, NiteHandId* pNewHandId);
                    mHandTracker->startHandTracking(gestures[i].getCurrentPosition(), &newId);
                }
            }
    
            // 获取定位手。
            const nite::Array<nite::HandData>& hands= mHandFrame.getHands();
            for (int i = 0; i < hands.getSize(); ++i)
            {
                const nite::HandData& user = hands[i];
    
                if (!user.isTracking())
                {
                    cout << "Lost hand %d\n" << user.getId();
                    nite::HandId id = user.getId();
                }
                else
                {
                    if (user.isNew())
                    {
                        cout << "Found hand %d\n" << user.getId();
                    }
                    else
                    {
                        cout << "Hand ID:" << hands[i].getId()
                            <<hands[i].getPosition().x << "," 
                            << hands[i].getPosition().y << ","
                            << hands[i].getPosition().z << endl;
                        float x, y;
    
                        // 将手心坐标转换映射到深度坐标中
                        mHandTracker->convertHandCoordinatesToDepth(hands[i].getPosition().x, hands[i].getPosition().y,
                            hands[i].getPosition().z, &x, &y);
    
                        // 将深度数据转换成OpenCV格式
                        const cv::Mat mHandDepth( mHandFrame.getDepthFrame().getHeight(), mHandFrame.getDepthFrame().getWidth(), CV_16UC1, 
                            (void*)mHandFrame.getDepthFrame().getData());
    
                        // 为了让深度图像显示的更加明显一些,将CV_16UC1 ==> CV_8U格式
                        cv::Mat mScaledHandDepth;
                        mHandDepth.convertTo( mScaledHandDepth, CV_8U, 255.0 / 10000 );
    
                        // 提取以手心为中心,200*200大小的图像
                        cv::Mat mHandsizeDepth = mScaledHandDepth(Rect(x - 100, y -100 , 200, 200));
    
                        // 显示手的图像
                        cv::imshow( "Hand Image", mHandsizeDepth );
                    }
                }
    
            }
            // 终止快捷键
            if( cv::waitKey(1) == 'q')
                break;
        }
    
        // 关闭Frame
        mHandFrame.release();
    
        // 关闭跟踪器
        mHandTracker->destroy();
    
        // 关闭NITE环境
        nite::NiTE::shutdown();
    
        return 0;        
    }

    上图

    结合程序注释和之前的博文内容,我想最后一个程序应该挺好理解的。根据自己的感觉走,感觉写代码,没做封装、优化、重构,完全是面向过程,而且肯定还存在细节的问题,会在后面进一步优化的。

        写的粗糙,欢迎指正批评~~~

  • 相关阅读:
    二叉树(python3版)
    第九章:树回归
    第八章:线性回归
    第七章:集成学习(利用AdaBoost元算法...)
    第六章:支持向量机(SVM)
    第五章:逻辑回归(Logistic 回归)
    第四章:朴素贝叶斯(bayes)
    win8 webview 无法响应部分页面点击事件
    无法激活Windows应用商店应用程序,"XXXXXXXXX"激活请求失败,错误为"应用未启动".
    无法激活windows应用商店应用程序,应用进程已启动,但激活请求失败,错误为“应用未启动”
  • 原文地址:https://www.cnblogs.com/yemeishu/p/2857593.html
Copyright © 2020-2023  润新知