kinect+opencv+mfc读取深度和彩色摄像头及截图

标签: kinect opencv mfc
654人阅读 评论(0) 收藏 举报
分类:

接着上面那一篇读彩色摄像头的。http://blog.csdn.net/u013948010/article/details/78289073
在其基础上加上了定时器和读深度摄像头即截图功能。最终结果图是酱紫的:
这里写图片描述
截图结果
这里写图片描述

设置定时器

由于好像循环读取并不是很好,所以把打开摄像头和读取视频的代码分开了,并设了一个定时器。当然其中避免不了把一些变量设成全局变量的啦。
定时器

void CopentestDlg::OnTimer(UINT_PTR nIDEvent)
{
        if (1 == nIDEvent) {
        CaptureVideo(); //捕捉自带摄像头
    }
    else if (2 == nIDEvent) {
        CaptureKinectVideo(); //捕捉彩色摄像头
    }
    else if (3 == nIDEvent) {
        CaptureKinectDepthVideo(); //捕捉深度摄像头
    }
    CDialog::OnTimer(nIDEvent);
}

初始化摄像头

void CopentestDlg::OnBnClickedButton4()
{
    // TODO: 在此添加控件通知处理程序代码
    //2、定义事件句柄   
    //创建读取下一帧的信号事件句柄,控制KINECT是否可以开始读取下一帧数据  
    nextColorFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    colorStreamHandle = NULL; //保存图像数据流的句柄,用以提取数据   
                              //3、打开KINECT设备的彩色图信息通道,并用colorStreamHandle保存该流的句柄,以便于以后读取  
    hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480,
        0, 2, nextColorFrameEvent, &colorStreamHandle);
    if (FAILED(hr))//判断是否提取正确   
    {
        AfxMessageBox(_T("读取错误"));
        NuiShutdown();
        return;
    }
    CRect rect;
    CWnd *pWnd = GetDlgItem(IDC_STATIC);
    pWnd->GetClientRect(&rect); //获取控件大小
    x = rect.Width();
    y = rect.Height();
    //4、开始读取彩色图数据   
    //追加文本  
    pEdit->ReplaceSel(_T("开始读取kinect彩色摄像头数据\r\n"));
    SetTimer(2, 25, NULL); //定时器,定时时间和帧率一致
}

读取摄像头数据

const NUI_IMAGE_FRAME * pImageFrame = NULL;
    //4.1、无限等待新的数据,等到后返回  
    if (WaitForSingleObject(nextColorFrameEvent, INFINITE) == 0)
    {
        //4.2、从刚才打开数据流的流句柄中得到该帧数据,读取到的数据地址存于pImageFrame  
        hr = NuiImageStreamGetNextFrame(colorStreamHandle, 0, &pImageFrame);
        if (FAILED(hr))
        {
            AfxMessageBox(_T("不能获取彩色图像"));
            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];
                }
            }
            cv::Mat dst;
            cv::resize(image, dst, cv::Size(x, y), 0, 0, 1);
            cv::imshow("view", dst);
        }
        else
        {
            AfxMessageBox(_T("获取数据无效"));
        }
        //5、这帧已经处理完了,所以将其解锁  
        pTexture->UnlockRect(0);
        //6、释放本帧数据,准备迎接下一帧   
        NuiImageStreamReleaseFrame(colorStreamHandle, pImageFrame);
    }

开深度摄像头

深度摄像头其实和彩色摄像头的获取非常非常类似,只需要修改其中几个地方,首先初始化变为全局初始化写在OnInitDialog()中,改写为

hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR | NUI_INITIALIZE_FLAG_USES_DEPTH); //初始化彩色和深度图像

创建并两个视频小窗口

    cvNamedWindow("view", CV_WINDOW_AUTOSIZE);
    cvNamedWindow("depth", CV_WINDOW_AUTOSIZE);
    HWND hWnd = (HWND)cvGetWindowHandle("view");
    HWND hParent = ::GetParent(hWnd);
    ::SetParent(hWnd, GetDlgItem(IDC_STATIC)->m_hWnd);
    ::ShowWindow(hParent, SW_HIDE);//隐藏父窗口

    HWND hWndDept = (HWND)cvGetWindowHandle("depth");
    HWND hParentDept = ::GetParent(hWndDept);
    ::SetParent(hWndDept, GetDlgItem(IDC_Dept)->m_hWnd);
    ::ShowWindow(hParentDept, SW_HIDE);//隐藏父窗口

然后深度摄像头获取,和彩色非常相似

void CopentestDlg::OnBnClickedButton5()
{
    // 打开深度摄像头
    //2、定义事件句柄   
    //创建读取下一帧的信号事件句柄,控制KINECT是否可以开始读取下一帧数据  
    nextDepthFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    //深度图像事件句柄
    depthStreamHandle = NULL;
    //实例打开数据流,这里NUI_IMAGE_TYPE_DEPTH表示深度图像
    hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH, NUI_IMAGE_RESOLUTION_640x480, 0, 2, nextDepthFrameEvent, &depthStreamHandle);
    if (FAILED(hr))//判断是否提取正确   
    {
        AfxMessageBox(_T("读取深度错误"));
        NuiShutdown();
        return;
    }
    pEdit->ReplaceSel(_T("开始读取kinect深度摄像头数据\r\n"));
    CRect rect;
    CWnd *pWnd = GetDlgItem(IDC_Dept);
    pWnd->GetClientRect(&rect); //获取控件大小
    xd = rect.Width();
    yd = rect.Height();
    SetTimer(3, 25, NULL); //定时器,定时时间和帧率一致
}
void CopentestDlg::CaptureKinectDepthVideo()
{
    const NUI_IMAGE_FRAME *pImageFrame_depth = NULL;
    //深度图像的处理
    if (WaitForSingleObject(nextDepthFrameEvent, INFINITE) == 0)
    {
        hr = NuiImageStreamGetNextFrame(depthStreamHandle, 0, &pImageFrame_depth);
        if (FAILED(hr))
        {
            AfxMessageBox(_T("不能读取深度图像"));
            NuiShutdown();
            return ;
        }
        INuiFrameTexture * pTexture = pImageFrame_depth->pFrameTexture;
        NUI_LOCKED_RECT LockedRect;
        //7.3、提取数据帧到LockedRect,它包括两个数据对象:pitch每行字节数,pBits第一个字节地址  
        //并锁定数据,这样当我们读数据的时候,kinect就不会去修改它  
        pTexture->LockRect(0, &LockedRect, NULL, 0);
        //7.4、确认获得的数据是否有效  
        if (LockedRect.Pitch != 0)
        {
            //7.5、将数据转换为OpenCV的Mat格式  
            for (int i = 0; i<depthImage.rows; i++)
            {
                uchar *ptr = depthImage.ptr(i);  //第i行的指针  
                                                 //每个字节代表一个颜色信息,直接使用uchar  
                uchar *pBuffer = (uchar*)(LockedRect.pBits) + i * LockedRect.Pitch;
                USHORT *pBufferRun = (USHORT *)pBuffer;//这里需要转换,因为每个深度数据是2个字节,应将BYTE转成USHORT  
                for (int j = 0; j<depthImage.cols; j++)
                {
                    ptr[j] = 255 - (BYTE)(256 * pBufferRun[j] / 0x1fff); //将数据归一化处理*  
                }
            }
            cv::Mat dst;
            cv::resize(depthImage, dst, cv::Size(xd, yd), 0, 0, 1);
            cv::imshow("depth", dst);

        }
        else
        {
            AfxMessageBox(_T("获取数据无效"));
        }
    //8、这帧已经处理完了,所以将其解锁  
    pTexture->UnlockRect(0);
    //9、释放本帧数据,准备迎接下一帧  
    NuiImageStreamReleaseFrame(depthStreamHandle, pImageFrame_depth);
    }
}

写一个炫酷的小框框写提示信息

这里用到了Edit Control在工具栏内可以找到,画出来是这样的

这里写图片描述

然后初始化一下,仍然是写在上面提到的初始化函数中

/*初始化编辑框*/
    pEdit = (CEdit*)GetDlgItem(IDC_EDIT1);
    int nLength = pEdit->GetWindowTextLength();
    //选定当前文本的末端  
    pEdit->SetSel(nLength, nLength);

然后就可以愉快地写内容了

pEdit->ReplaceSel(_T(“打开kinect失败,不能使用kinect读取图像\r\n”));

截图功能

先画一个截图按钮,然后给按钮添加事件处理函数。主要依靠imwrite()函数实现截图并保存的功能

void CopentestDlg::OnBnClickedScreenshot()
{   
    std::string basePath = "./images/";
    std::string colorPathPrefix = "Color";
    std::string depthPathPrefix = "Depth";
    std::string commonPathSuffix = ".jpg";
    std::stringstream ss;
    ss << basePath << count << "-" << colorPathPrefix << commonPathSuffix;
    std::string colorImagePath = ss.str();
    imwrite(colorImagePath, image);

    std::stringstream ssd;
    ssd << basePath<<count<<"-" << depthPathPrefix << commonPathSuffix;
    std::string depthImagePath = ssd.str();
    imwrite(depthImagePath, depthImage);
    count++;
    pEdit->ReplaceSel(_T("截图成功,已保存到images文件夹中\r\n"));
}

程序源码

https://github.com/imcy/kinect

查看评论

KINECT+opencv(2)基于骨骼信息对视频进行动作识别

KINECT+opencv基于骨骼信息对视频进行动作识别环境:kinect1.7+opencv2.4+vc2015 使用kinect获取并按批处理三维空间内的骨骼信息 基于视频帧差计算各关节运动向量并...
  • Daky_u
  • Daky_u
  • 2016-05-14 14:53:57
  • 6310

结合Kinect v2.0+ VS2012+openCV2.4.9,将Kinect v2.0深度帧存到openCV2.4.9中,并输出到指定文件夹

  • 2015年03月31日 10:05
  • 9.38MB
  • 下载

解觉opencv中videocapture不能打开kinect的问题

  • 2014年04月12日 13:13
  • 1.76MB
  • 下载

Kinect视频的保存和回放(二)

目的:保存kinect的视频数据,并回放,以便于动作的剪裁 进展:完成了视频的保存(avi格式),回放以及目标段的剪裁 现存问题:文件没有经过压缩,数据量大      之前的程序启动后...
  • baizhengbiao
  • baizhengbiao
  • 2012-08-26 16:55:54
  • 4979

使用Kinect V2进行录制视频

使用Kinect 2.0 进行视频的录制代码。#include #include #include #include #include #include "videoGet\videopro...
  • Haley_Xu_ANN
  • Haley_Xu_ANN
  • 2017-02-28 19:54:29
  • 1500

kinect2.0(二)读取彩色图像

读取彩色图像步骤1.获取kinect传感器 2.打开传感器 3.获取彩色图像信息传感器 4. 打开彩色图像帧读取器 5.获得最近的一帧 6. 将彩色图像转换为M...
  • ktigerhero3
  • ktigerhero3
  • 2015-11-19 22:04:54
  • 3128

Opencv+Kinect2.0 的环境配置和获取彩色图

一、环境的配置 在属性管理器窗口中找到Microsoft.Cpp.Win32.user这一项,双击进入。 然后在 通用属性,VC++目录下 默认Opencv已经配置好,在包含目录中添加: $...
  • qq_22033759
  • qq_22033759
  • 2015-09-13 19:21:21
  • 3442

kinect2.0开发(一) 读取深度图像

读取深度图像
  • ktigerhero3
  • ktigerhero3
  • 2015-11-19 17:33:09
  • 7497

Kinect入门(1)——显示彩色图像数据流

进行本节的前提是已配置好Kinect的开发环境。废话不多说,直接进入正题!Kinect+VS2012显示彩色图像数据流1、新建C# WPF应用程序,项目名随便写即可。2、在解决方案“….”里右击“引用...
  • jnulzl
  • jnulzl
  • 2015-09-14 14:55:31
  • 2201

读取并显示Kinect彩色图和深度图的三种方法:代码

  • 2013年12月09日 22:34
  • 36.19MB
  • 下载
    个人资料
    持之以恒
    等级:
    访问量: 1万+
    积分: 650
    排名: 7万+
    最新评论