牛骨文教育服务平台(让学习变的简单)
博文笔记

kincet 读取深度图像

创建时间:2017-07-09 投稿人: 浏览次数:644

  win7 64位+opencv2.4.9+VS2010+kinect SDK1.8环境配置在上一篇博客中已经完成,现在开始进行第一个实验,使用kinect摄像头读取深度图像,将其转换为opencv的mat结构进行存储并显示。

  强行背下了几十行代码,代码中涉及到的函数含义在以下博客中有详细介绍:

  http://blog.csdn.net/leowangzi/article/details/6604513 微软Kinect for windows SDK 使用教程-NUI部分

#include <windows.h>  
#include <iostream>  
#include <NuiApi.h>  
#include <opencv2/opencv.hpp>  
  
using namespace std;  
using namespace cv;  

int main(int argc, char *argv[])  
{  
    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 hr;  
    }  
  
    // 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 hr;  
    }  
    namedWindow("depthImage", CV_WINDOW_AUTOSIZE);  
  
    // 4. 开始读取深度数据  
    while (true)  
    {  
        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 -1;  
            }  
  
            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 - (BYTE)(256 * pBuffer[j] / 0x0fff);  // 直接将数据归一化处理 
						
                    }  
                } 
     
                imshow("depthImage", image);    //在此显示的位两个摄像头度到的两幅图像。。。怎么处理为一副图像?
            }  
            else  
            {  
                cout << "Buffer length of received texture is bogus
" << endl;  
            }  
  
            // 5. 这一帧已经处理完了,所以将其解锁  
            pTexture->UnlockRect(0);  
  
            // 6. 释放本帧数据,准备迎接下一帧  
            NuiImageStreamReleaseFrame(depthStreamHandle, pImageFrame);  
        }  
        if (cvWaitKey(20) == 27)  
        {  
            break;  
        }  
    }  
  
    // 7. 关闭NUI链接 
	NuiShutdown();
    return 0;  
}  

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。