• 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驱动共存的问题,剩下的就好解决了。最后说明的是:根据自己的感觉写代码,没做封装、优化、重构,完全是面向过程,而且肯定还存在细节的问题,会在后面进一步优化的。    写的粗糙,欢迎指正批评~~~

  • 相关阅读:
    深入浅出理解索引结构
    SQL数据库碎片检查DBCC SHOWCONTIG含义
    NHibernate和SqlImage
    C#中验证sql语句的方法 (SET PARSEONLY 与SET NOEXEC )
    Webbrowser控件判断网页加载完毕的简单方法
    如何将一个HTML页面嵌套在另一个页面中
    WCF REST Service: InstanceContextMode.PerCall 不管用,无法实现并发
    linux中修改ssh端口
    linux修改主机名(不重启)
    centos使用光盘作为本地的yum源
  • 原文地址:https://www.cnblogs.com/yemeishu/p/2957403.html
Copyright © 2020-2023  润新知