談談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;        
}

上圖

結合程序注釋和之前的博文內容,我想最后一個程序應該挺好理解的。根據自己的感覺走,感覺寫代碼,沒做封裝、優化、重構,完全是面向過程,而且肯定還存在細節的問題,會在后面進一步優化的。

    寫的粗糙,歡迎指正批評~~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM