2017年2月22日 星期三

使用Visual studio 2012 開啟Kinect攝影機並顯示色彩圖及深度圖

開發環境 : Visual studio 2012 、Kinect V1、Win10、OpenCv 2.4.7、Kinect SDK v1.8

平台 : x64

屬性 :  VC++目錄 - Include目錄: C:\Program Files\Microsoft SDKs\Kinect\v1.8\inc
                                                       C:\opencv\build\include
                                                       C:\opencv\build\include\opencv
                                                       C:\opencv\build\include\opencv2
                               -程式庫目錄 : C:\opencv\build\x64\vc11\lib
                                                       C:\Program Files\Microsoft SDKs\Kinect\v1.8\lib\amd64
           連結器        -其他相依性: opencv_core247d.lib
                                                     opencv_imgproc247d.lib
                                                     opencv_highgui247d.lib
                                                     opencv_ml247d.lib
                                                     opencv_video247d.lib
                                                     opencv_features2d247d.lib
                                                     opencv_calib3d247d.lib
                                                     opencv_objdetect247d.lib
                                                     opencv_contrib247d.lib
                                                     opencv_legacy247d.lib
                                                     opencv_flann247d.lib
                                                     opencv_nonfree247d.lib
                                                     Kinect10.lib

參考網站 : Kinect开发学习笔记



#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <NuiApi.h>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;
char ModeSwitch='0';

void openKinect_RGB();
void openKinect_Depth();
void openKinect_RGBandDepth();

int main()
{
while(ModeSwitch!='Q'&& ModeSwitch!='q')
{
cout << endl;
cout << "Welcome to use this program." << endl << endl;
cout << "<<   Main Control Menu   >>"<< endl;
cout << "Press C to open RGB Camera." << endl;
cout << "Press D to open Depth Camera." << endl;
cout << "Press A to open RGB & Depth Camera." << endl;
cout << "Press Q to quit the program." << endl;

cout << endl;

ModeSwitch=getch();

if(ModeSwitch=='C' ||ModeSwitch=='c')
{
openKinect_RGB();
system("cls");
}
else if(ModeSwitch=='D' ||ModeSwitch=='d')
{
openKinect_Depth();
system("cls");
}
else if(ModeSwitch=='A' ||ModeSwitch=='a')
{
openKinect_RGBandDepth();
system("cls");
}
}

return 0;
}

void openKinect_RGB()
{
Mat image;
    image.create(480, 640, CV_8UC3);
//image.create(960, 1280, CV_8UC3);
 
    //1、初始化NUI
    HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR);
    if (FAILED(hr))
    {
        cout<<"NuiInitialize failed"<<endl;
        return ;
    }

    //2、定义事件句柄
    //创建读取下一帧的信号事件句柄,控制KINECT是否可以开始读取下一帧数据
    HANDLE nextColorFrameEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    HANDLE colorStreamHandle = NULL; //保存图像数据流的句柄,用以提取数据
 
    //3、打开KINECT设备的彩色图信息通道,并用colorStreamHandle保存该流的句柄,以便于以后读取
    hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480,
                            0, 2, nextColorFrameEvent, &colorStreamHandle);
//hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_1280x960,
    //                        0, 2, nextColorFrameEvent, &colorStreamHandle);
    if( FAILED( hr ) )//判断是否提取正确
    {
        cout<<"Could not open color image stream video"<<endl;
        NuiShutdown();
        return ;
    }
    namedWindow("colorImage", CV_WINDOW_AUTOSIZE);
 
    //4、开始读取彩色图数据
    while(1)
    {
        const NUI_IMAGE_FRAME * pImageFrame = NULL;

        //4.1、无限等待新的数据,等到后返回
        if (WaitForSingleObject(nextColorFrameEvent, INFINITE)==0)
        {
            //4.2、从刚才打开数据流的流句柄中得到该帧数据,读取到的数据地址存于pImageFrame
            hr = NuiImageStreamGetNextFrame(colorStreamHandle, 0, &pImageFrame);
            if (FAILED(hr))
            {
                cout<<"Could not get color image"<<endl;
                NuiShutdown();
                return ;
            }

            INuiFrameTexture * pTexture = pImageFrame->pFrameTexture;
            NUI_LOCKED_RECT LockedRect;

            //4.3、提取数据帧到LockedRect,它包括两个数据对象:pitch每行字节数,pBits第一个字节地址
            //并锁定数据,这样当我们读数据的时候,kinect就不会去修改它
            pTexture->LockRect(0, &LockedRect, NULL, 0);
            //4.4、确认获得的数据是否有效
            if( LockedRect.Pitch != 0 )
            {
                //4.5、将数据转换为OpenCV的Mat格式
                for (int i=0; i<image.rows; i++)
                {
                    uchar *ptr = image.ptr<uchar>(i);  //第i行的指针
                   
                    //每个字节代表一个颜色信息,直接使用uchar
                    uchar *pBuffer = (uchar*)(LockedRect.pBits) + i * LockedRect.Pitch;
                    for (int j=0; j<image.cols; j++)
                    {
                        ptr[3*j] = pBuffer[4*j];  //内部数据是4个字节,0-1-2是BGR,第4个现在未使用
                        ptr[3*j+1] = pBuffer[4*j+1];
                        ptr[3*j+2] = pBuffer[4*j+2];
                    }
                }
                imshow("colorImage", image); //显示图像
            }
            else
            {
                cout<<"Buffer length of received texture is bogus\r\n"<<endl;
            }

            //5、这帧已经处理完了,所以将其解锁
            pTexture->UnlockRect(0);
            //6、释放本帧数据,准备迎接下一帧
            NuiImageStreamReleaseFrame(colorStreamHandle, pImageFrame );
        }

        if (cvWaitKey(20) == 27)
{
destroyWindow("colorImage");
break;
}

    }
    //7、关闭NUI链接
    NuiShutdown();
return;
}

void openKinect_Depth()
{
Mat image;
    //这里我们用灰度图来表述深度数据,越远的数据越暗。
    image.create(480, 640, CV_8UC1);
 
    //1、初始化NUI,注意:这里传入的参数就不一样了,是DEPTH
    HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH);
    if (FAILED(hr))
    {
        cout<<"NuiInitialize failed"<<endl;
        return ;
    }

    //2、定义事件句柄
    //创建读取下一帧的信号事件句柄,控制KINECT是否可以开始读取下一帧数据
    HANDLE nextColorFrameEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    HANDLE depthStreamHandle = NULL;
 
    //3、打开KINECT设备的深度图信息通道,并用depthStreamHandle保存该流的句柄,以便于以后读取
    hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH, NUI_IMAGE_RESOLUTION_640x480,
                            0, 2, nextColorFrameEvent, &depthStreamHandle);
    if( FAILED( hr ) )//判断是否提取正确
    {
        cout<<"Could not open color image stream video"<<endl;
        NuiShutdown();
        return ;
    }
    namedWindow("depthImage", CV_WINDOW_AUTOSIZE);
 
    //4、开始读取深度数据
    while(1)
    {
        const NUI_IMAGE_FRAME * pImageFrame = NULL;

        //4.1、无限等待新的数据,等到后返回
        if (WaitForSingleObject(nextColorFrameEvent, INFINITE)==0)
        {
            //4.2、从刚才打开数据流的流句柄中得到该帧数据,读取到的数据地址存于pImageFrame
            hr = NuiImageStreamGetNextFrame(depthStreamHandle, 0, &pImageFrame);
            if (FAILED(hr))
            {
                cout<<"Could not get depth image"<<endl;
                NuiShutdown();
                return ;
            }

            INuiFrameTexture * pTexture = pImageFrame->pFrameTexture;
            NUI_LOCKED_RECT LockedRect;

            //4.3、提取数据帧到LockedRect,它包括两个数据对象:pitch每行字节数,pBits第一个字节地址
            //并锁定数据,这样当我们读数据的时候,kinect就不会去修改它
            pTexture->LockRect(0, &LockedRect, NULL, 0);
            //4.4、确认获得的数据是否有效
            if( LockedRect.Pitch != 0 )
            {
                //4.5、将数据转换为OpenCV的Mat格式
                for (int i=0; i<image.rows; i++)
                {
                    uchar *ptr = image.ptr<uchar>(i);  //第i行的指针
                   
                    //深度图像数据含有两种格式,这里像素的低12位表示一个深度值,高4位未使用;
                    //注意这里需要转换,因为每个数据是2个字节,存储的同上面的颜色信息不一样,
                    uchar *pBufferRun = (uchar*)(LockedRect.pBits) + i * LockedRect.Pitch;
                    USHORT * pBuffer = (USHORT*) pBufferRun;
                     
                    for (int j=0; j<image.cols; j++)
                    {
                        ptr[j] = 255 - (uchar)(256 * pBuffer[j]/0x0fff);  //直接将数据归一化处理
                    }
                }

//標記出中心點
circle(image, Point(320,240), 2,  Scalar(0,255,0), -1);
//讀取並輸出中心點之深度值
uchar *ptr_center = image.ptr<uchar>(240);
uchar *pBufferRun = (uchar*)(LockedRect.pBits) + 240 * LockedRect.Pitch;
                USHORT * pBuffer = (USHORT*) pBufferRun;
system("cls");
cout << "depth = " << pBuffer[320];

                imshow("depthImage", image); //显示图像
            }
            else
            {
                cout<<"Buffer length of received texture is bogus\r\n"<<endl;
            }

            //5、这帧已经处理完了,所以将其解锁
            pTexture->UnlockRect(0);
            //6、释放本帧数据,准备迎接下一帧
            NuiImageStreamReleaseFrame(depthStreamHandle, pImageFrame );
        }
        if (cvWaitKey(20) == 27)
{
destroyWindow("depthImage");
            break;
}
 
    }
    //7、关闭NUI链接
    NuiShutdown();
}

void openKinect_RGBandDepth()
{
Point center(0,0);
Mat colorImage,depthImage;
    colorImage.create(480, 640, CV_8UC3);
depthImage.create(480, 640, CV_8UC1);

HANDLE colorEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    HANDLE depthEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
HANDLE colorStreamHandle = NULL;
    HANDLE depthStreamHandle = NULL;

//初始化NUI
    HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR | NUI_INITIALIZE_FLAG_USES_DEPTH);
    if (FAILED(hr))
    {
        cout<<"NuiInitialize failed"<<endl;
        return ;
    }

    hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480,
                            0, 2, colorEvent, &colorStreamHandle);
    if( FAILED( hr ) )//判断是否提取正确
    {
        cout<<"Open the color Stream failed !"<<endl;
        NuiShutdown();
        return ;
    }
hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH, NUI_IMAGE_RESOLUTION_640x480,
                            0, 2, depthEvent, &depthStreamHandle);
    if( FAILED( hr ) )//判断是否提取正确
    {
        cout<<"Open the Depth Stream failed !"<<endl;
        NuiShutdown();
        return ;
    }

while(true)
{

const NUI_IMAGE_FRAME *colorFrame = NULL;
const NUI_IMAGE_FRAME *depthFrame = NULL;
if (WaitForSingleObject(colorEvent, INFINITE)==0 && WaitForSingleObject(depthEvent, INFINITE)==0)
        {
NuiImageStreamGetNextFrame(colorStreamHandle, 0, &colorFrame);
INuiFrameTexture *pTexture_color = colorFrame->pFrameTexture;
NuiImageStreamGetNextFrame(depthStreamHandle, 0, &depthFrame);
INuiFrameTexture *pTexture_depth = depthFrame->pFrameTexture;

NUI_LOCKED_RECT LockedRect_color;
pTexture_color->LockRect(0, &LockedRect_color, NULL, 0);
NUI_LOCKED_RECT LockedRect_depth;
pTexture_depth->LockRect(0, &LockedRect_depth, NULL, 0);

            //4.4、确认获得的数据是否有效
            if( LockedRect_color.Pitch != 0 )
            {
                //4.5、将数据转换为OpenCV的Mat格式
                for (int i=0; i<colorImage.rows; i++)
                {
                    uchar *ptr = colorImage.ptr<uchar>(i);  //第i行的指针
                   
                    //每个字节代表一个颜色信息,直接使用uchar
                    uchar *pBuffer = (uchar*)(LockedRect_color.pBits) + i * LockedRect_color.Pitch;
                    for (int j=0; j<colorImage.cols; j++)
                    {
                        ptr[3*j] = pBuffer[4*j];  //内部数据是4个字节,0-1-2是BGR,第4个现在未使用
                        ptr[3*j+1] = pBuffer[4*j+1];
                        ptr[3*j+2] = pBuffer[4*j+2];
                    }
                }
for (int i=0; i<depthImage.rows; i++)
                {
                    uchar *ptr = depthImage.ptr<uchar>(i);  //第i行的指针
                   
                    //深度图像数据含有两种格式,这里像素的低12位表示一个深度值,高4位未使用;
                    //注意这里需要转换,因为每个数据是2个字节,存储的同上面的颜色信息不一样,
                    uchar *pBufferRun = (uchar*)(LockedRect_depth.pBits) + i * LockedRect_depth.Pitch;
                    USHORT * pBuffer = (USHORT*) pBufferRun;
                     
                    for (int j=0; j<depthImage.cols; j++)
                    {
                        ptr[j] = 255 - (uchar)(256 * pBuffer[j]/0x0fff);  //直接将数据归一化处理
                    }
                }


                imshow("colorImage", colorImage); //显示图像
imshow("depthImage", depthImage); //显示图像
            }
            else
            {
                cout<<"Buffer length of received texture is bogus\r\n"<<endl;
            }


            pTexture_color->UnlockRect(0);
pTexture_depth->UnlockRect(0);
            NuiImageStreamReleaseFrame(colorStreamHandle, colorFrame );
NuiImageStreamReleaseFrame(depthStreamHandle, depthFrame );
        }

if (cvWaitKey(20) == 27)
{
destroyWindow("colorImage");
destroyWindow("depthImage");
break;
}
}
NuiShutdown();
return;


}

沒有留言:

張貼留言