OpenNI2下簡單操作兩個體感設備(Xtion與Kinect for Xbox 360)


主要內容:

一、設備與驅動准備

  最近忙着寫論文,已好長時間沒瞎寫了,這兩天偶然看到一篇有關OpenNI2操作兩個體感設備的文章,自己復制粘貼運行下看了效果挺好的,所以我大膽的搬過來,和大家分享分享~~~

  設備准備:一個ASUS Xtion;一個Kinect for Xbox360;

  驅動准備:我是win7下運行的,只要在設備管理器中顯示如下效果,就沒問題;要是有出現一個顯示黃的,那就表示其中有一個顯示不了,我目前的做法是:反復拔了再插,插了再拔,直到顯示如下效果就OK;

二、代碼演示

  在之前都是用到一個體感設備進行開發,但也有人拿兩個把玩着,所以如何同時讓兩個都運行起來?

  在OpenNI2中提供了一個OpenNI::enumerateDevices函數原型是這樣的:

    /**
    Fills up an array of @ref DeviceInfo objects with devices that are available.
    @param [in,out] deviceInfoList An array to be filled with devices.
    */
    static void enumerateDevices(Array<DeviceInfo>* deviceInfoList)
    {
        OniDeviceInfo* m_pDeviceInfos;
        int m_deviceInfoCount;
        oniGetDeviceList(&m_pDeviceInfos, &m_deviceInfoCount);
        deviceInfoList->_setData((DeviceInfo*)m_pDeviceInfos, m_deviceInfoCount, true);
        oniReleaseDeviceList(m_pDeviceInfos);
    }

英語學的不好,大概的意思是將可使用的divices設備信息保存到Array<DeviceInfo>* deviceInfoList中吧~通過看oniGetDeviceList函數:

/**
 * Get the list of currently connected device.
 * Each device is represented by its OniDeviceInfo.
 * pDevices will be allocated inside.
 */
ONI_C_API OniStatus oniGetDeviceList(OniDeviceInfo** pDevices, int* pNumDevices);

  通過Array<DeviceInfo>* deviceInfoList,我們就可以得到DeviceInfo信息操作Device了,其中DeviceInfo包括設備Uri,供應商名,供應商ID,設備Id,設備名:

class DeviceInfo : private OniDeviceInfo
{
public:
    /** 
    Returns the device URI.  URI can be used by @ref Device::open to open a specific device. 
    The URI string format is determined by the driver.
    */
    const char* getUri() const { return uri; }
    /** Returns a the vendor name for this device. */
    const char* getVendor() const { return vendor; }
    /** Returns the device name for this device. */
    const char* getName() const { return name; }
    /** Returns the USB VID code for this device. */
    uint16_t getUsbVendorId() const { return usbVendorId; }
    /** Returns the USB PID code for this device. */
    uint16_t getUsbProductId() const { return usbProductId; }

    friend class Device;
    friend class OpenNI;
};

  有了這些信息就可以看目前連接的設備的信息了,看代碼:

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

    // 獲取設備信息  
    Array<DeviceInfo> aDeviceList;  
    OpenNI::enumerateDevices( &aDeviceList );   
    
    // output information  
    //vector<CDevice>  vDevices;  
    cout << "電腦上連接着 " << aDeviceList.getSize()       << " 個體感設備." << endl;  
    
    for( int i = 0; i < aDeviceList.getSize(); ++ i )  
    {    
        cout << "設備 " << i << endl;    
        const DeviceInfo& rDevInfo = aDeviceList[i];      
        cout << "設備名: " << rDevInfo.getName() << endl;
        cout << "設備Id: " <<  rDevInfo.getUsbProductId() << endl;
        cout << "供應商名: "<< rDevInfo.getVendor() << endl;     
        cout << "供應商Id: " << rDevInfo.getUsbVendorId() << endl;    
        cout << "設備URI: " << rDevInfo.getUri() << endl;     

    }
        system("pause"); // 編譯運行之后可以
        OpenNI::shutdown(); 
        return 0;
}

  顯示效果:

  接着在獲取Kinect和Xtion信息之后,就可以驅動他們運行了,通過設備Uri驅動,估計大家都懂了,然后獲得它們各自的深度信息流數據,再利用OpenCV進行處理,直接上代碼:

// MoreDevice.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h"

// 標准庫頭文件
#include <iostream>
#include <string>
#include <vector> 
// OpenCV頭文件
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp> 
// OpenNI頭文件
#include <OpenNI.h> 
// namespace
using namespace std;
using namespace openni;

class CDevice{
public:  
    const char* devicename; 
    Device*       pDevice;  
    VideoStream*  pDepthStream;   
    
    CDevice( int idx, const char* uri, const char* deviceName)  
    {    
        devicename = deviceName;

        // 創建Device
        pDevice = new Device();    
        // 打開指定Uri設備
        pDevice->open( uri );  

        // 創建深度數據量
        pDepthStream = new VideoStream();  
        pDepthStream->create( *pDevice, SENSOR_DEPTH );   

        // 創建OpenCV窗口
        cv::namedWindow( deviceName,  CV_WINDOW_AUTOSIZE );
        
        // 開始    
        pDepthStream->start();  
    }
}; 
int main( int argc, char **argv )
{  
    // 初始化OpenNI  
    OpenNI::initialize();

    // 獲取設備信息  
    Array<DeviceInfo> aDeviceList;  
    OpenNI::enumerateDevices( &aDeviceList );   
    
    // 將每個設備信息用CDevice類封裝  
    vector<CDevice>  vDevices;

    cout << "電腦上連接着 " << aDeviceList.getSize()       << " 個體感設備." << endl;  
    
    for( int i = 0; i < aDeviceList.getSize(); ++ i )  
    {    
        cout << "設備 " << i << endl;    
        const DeviceInfo& rDevInfo = aDeviceList[i];      
        cout << "設備名: " << rDevInfo.getName() << endl;
        cout << "設備Id: " <<  rDevInfo.getUsbProductId() << endl;
        cout << "供應商名: "<< rDevInfo.getVendor() << endl;     
        cout << "供應商Id: " << rDevInfo.getUsbVendorId() << endl;    
        cout << "設備URI: " << rDevInfo.getUri() << endl;     

        // 封裝類初始化,傳入設備名和設備Uri 
        CDevice mDev(i, aDeviceList[i].getUri(), aDeviceList[i].getName());    
        vDevices.push_back( mDev );  
    }    
    while( true )  
    {    
        for( vector<CDevice>::iterator itDev = vDevices.begin();         
            itDev != vDevices.end(); ++ itDev )    
        {      
            // 獲取深度圖像幀      
            VideoFrameRef vfFrame;      
            itDev->pDepthStream->readFrame( &vfFrame );        
            // 轉換成 OpenCV 格式      
            const cv::Mat mImageDepth( vfFrame.getHeight(), 
                vfFrame.getWidth(),                                
                CV_16UC1,                                 
                const_cast<void*>( vfFrame.getData() ) 
                );       
            // 從 [0,Max] 轉為 [0,255]      
            cv::Mat mScaledDepth;      
            mImageDepth.convertTo( mScaledDepth, CV_8U,   
                255.0 / itDev->pDepthStream->getMaxPixelValue() );      
            // 顯示圖像      
            cv::imshow( itDev->devicename, mScaledDepth );       
            vfFrame.release();    
        }  
        // 退出鍵    
        if( cv::waitKey( 1 ) == 'q' )      
            break;  
    }    
    // 停止時的操作  
    for( vector<CDevice>::iterator itDev = vDevices.begin();       
        itDev != vDevices.end(); ++ itDev )  
    {    
        itDev->pDepthStream->stop();    
        itDev->pDepthStream->destroy();    
        delete itDev->pDepthStream;         
        itDev->pDevice->close();    
        delete itDev->pDevice;  
    }  
    OpenNI::shutdown();
    return 0;
}

  顯示效果:

三、總結

  代碼挺簡單的,我自己碰到的問題主要是xtion和kinect驅動共存的問題,剩下的就好解決了。最后說明的是:根據自己的感覺寫代碼,沒做封裝、優化、重構,完全是面向過程,而且肯定還存在細節的問題,會在后面進一步優化的。    寫的粗糙,歡迎指正批評~~~


免責聲明!

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



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