• 谈谈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();

    下面是简单的右手骨骼坐标跟踪,并显示右手坐标信息的程序代码:

    // YeNITE2SimpleUsingOpenCV_Skeleton.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;
    
                    // 开始人体骨骼跟踪
                    mUserTracker.startSkeletonTracking( rUser.getId() );
                }
                
                // 获取骨骼坐标
                const nite::Skeleton& rSkeleton = rUser.getSkeleton();
                if( rSkeleton.getState() == nite::SKELETON_TRACKED )
                {
                    // 得到右手坐标
                    const nite::SkeletonJoint& righthand
                        = rSkeleton.getJoint( nite::JOINT_RIGHT_HAND );
                    const nite::Point3f& position = righthand.getPosition();
                    cout << "右手坐标: " << position.x << "/" << position.y << "/" << position.z << endl;
                }
    
            }
        }
    
        // 释放     
        mUserFrame.release();      
        
        // 关闭跟踪器
        mUserTracker.destroy();
    
        // 关闭NITE环境
        nite::NiTE::shutdown();
    
        return 0;
    }

        程序执行结果如下:

        但通过对上述程序代码观察发现,在对人体骨骼跟踪的时候,未做出(“投降”和“双手抱胸”)的动作,也可以获取骨骼坐标信息。难道在NITE2骨骼跟踪的时候,人体姿势检测是多余的吗?这个我的理解是:似乎姿势跟踪将会变成鸡肋(完全靠自己的想象。。。)。

        接着借助于OpenCV等常用工具库,看看骨骼坐标在深度图像下的定位和显示效果,直接上代码:

    // 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();
    
        // 创建User跟踪器
        nite::UserTracker* mUserTracker = new nite::UserTracker;
        mUserTracker->create();
    
        // 创建OpenCV图像窗口
        namedWindow( "Skeleton Image",  CV_WINDOW_AUTOSIZE );
    
        // 循环读取数据流信息并保存在HandFrameRef中
        nite::UserTrackerFrameRef mUserFrame;
    
        while( true )
        {
            // 读取Frame信息
            nite::Status rc = mUserTracker->readFrame(&mUserFrame);
            if (rc != nite::STATUS_OK)
            {
                cout << "GetNextData failed" << endl;
                return 0;
            }
    
            // 将深度数据转换成OpenCV格式
            const cv::Mat mHandDepth( mUserFrame.getDepthFrame().getHeight(), mUserFrame.getDepthFrame().getWidth(), CV_16UC1, 
                (void*)mUserFrame.getDepthFrame().getData());
    
            // 为了让深度图像显示的更加明显一些,将CV_16UC1 ==> CV_8U格式
            cv::Mat mScaledHandDepth, thresholdDepth;
            mHandDepth.convertTo( mScaledHandDepth, CV_8U, 255.0 / 10000 );
    
            // 二值化处理,为了显示效果明显
            cv::threshold(mScaledHandDepth, thresholdDepth, 50, 255, 0);
    
            // 从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;
    
                    // 开始人体骨骼跟踪
                    mUserTracker->startSkeletonTracking( rUser.getId() );
                }
    
                // 获取骨骼坐标
                const nite::Skeleton& rSkeleton = rUser.getSkeleton();
                if( rSkeleton.getState() == nite::SKELETON_TRACKED )
                {
                    // 只得到前8个骨骼点坐标
                    for(int i = 0; i < 8; i++)
                    {
                        // 得到骨骼坐标
                        const nite::SkeletonJoint& skeletonJoint
                            = rSkeleton.getJoint((nite::JointType)i);
                        const nite::Point3f& position = skeletonJoint.getPosition();
    
                        float depth_x, depth_y;
    
                        // 将骨骼点坐标映射到深度坐标中
                        mUserTracker->convertJointCoordinatesToDepth(position.x, position.y, position.z, &depth_x, &depth_y);
    
                        cv::Point point((int)depth_x, (int)depth_y);
    
                        // 将获取的深度图像中相对应的坐标点重新赋值为255.即在深度图像中显示出各个骨骼点。
                        thresholdDepth.at<uchar>(point) = 255;
                    }
                    
                    // 显示图像
                    cv::imshow( "Skeleton Image", thresholdDepth );
                }
    
            }
            
            // 终止快捷键
            if( cv::waitKey(1) == 'q')
                break;
        }
    
        // 关闭Frame
        mUserFrame.release();
    
        // 关闭跟踪器
        mUserTracker->destroy();
    
        // 关闭NITE环境
        nite::NiTE::shutdown();
    
        return 0;        
    }

    上图: 图上“白点”就是骨骼点。

        需要了解具体的骨骼点信息(位置、方向,以及可靠性等),可以看官网提供的参考文献。我觉得遗憾的是,目前提供的15个骨骼点坐标不包括了手腕等其它骨骼点、而且只能得到全身的,不能单独获取上半身骨骼坐标。

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

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

  • 相关阅读:
    二维数组输出10行杨辉三角
    二维数组的练习----求和
    数组的异常及处理
    二维数组在内存中的结构
    Ubuntu系统中安装Mercurial 以支持hg
    什么是插补、直线插补、联动与插补
    压力表(负压表...)
    常用接近开关的原理和分类
    VMware Ubuntu安装详细过程
    Redis+Spring缓存实例(windows环境,附实例源码及详解)
  • 原文地址:https://www.cnblogs.com/yemeishu/p/2862514.html
Copyright © 2020-2023  润新知