kinect+opencv+mfc读取彩色摄像头

纠结了一下午的kinect初尝试,算是有一点小成果了,觉得这方面资料比较少,打算写一下总结。

前期准备

1.先安装Kinect的SDK,这里采用的是SDK1.8(虽然都17年了,但是老设备还是得装1.8)之前装2.0引起了插入Kinect一直闪烁无法装驱动的问题。
2.装好SDK后可以看看里面的小示例啦,然后就是安装opencv,这里选的是3.0,然后配置一些环境变量
这里写图片描述
3.安装好opencv后可以建一个控制台程序测试一下,记得导入一下opencv的库

int main()
{
    IplImage * test;
    test = cvLoadImage("./1.jpg");//图片路径
    cvNamedWindow("test_demo", 1);
    cvShowImage("test_demo", test);
    cvWaitKey(0);
    cvDestroyWindow("test_demo");
    cvReleaseImage(&test);
    return 0;
}

开始一步步写MFC啦

1.创建一个mfc工程,创建步骤不细说了,参考
http://blog.csdn.net/sxlsxl119/article/details/51258998
先实现打开图片,写一个button处理函数如下所示。导入cvvImage类看上述文章教程

void CopentestDlg::OnBnClickedButton1()
{
    flag = false;
    // TODO: 在此添加控件通知处理程序代码
    AfxMessageBox(_T("点击了打开图片!"));
    IplImage *image = NULL; //原始图像
    if (image) cvReleaseImage(&image);
    image = cvLoadImage("./1.jpg", 1); //显示图片
    DrawPicToHDC(image, IDC_STATIC);
}

效果大概是这样的
这里写图片描述
2.再参考
http://blog.csdn.net/kh1445291129/article/details/50778913
实现一下电脑自带视频流的捕捉。注意这里在初始化函数OnInitDialog()添加了一部分代码用来隐藏事先创建好的视频框,在那个位置打开opencv的视频框如下:

    // TODO: 在此添加额外的初始化代码
    cvNamedWindow("view", CV_WINDOW_AUTOSIZE);
    HWND hWnd = (HWND)cvGetWindowHandle("view");
    HWND hParent = ::GetParent(hWnd);
    ::SetParent(hWnd, GetDlgItem(IDC_STATIC)->m_hWnd);
    ::ShowWindow(hParent, SW_HIDE);//隐藏父窗口
    flag = 1;
    kinectable = false;
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE

写一个button处理函数打开摄像头如下

void CopentestDlg::OnBnClickedButton2()
{
    // 点击打开电脑自带摄像头
    AfxMessageBox(_T("将打开摄像头"));
    flag = true;
    CRect rect;
    CWnd *pWnd = GetDlgItem(IDC_STATIC);
    pWnd->GetClientRect(&rect); //获取控件大小
    int x = rect.Width();
    int y = rect.Height();
    cv::VideoCapture capture(0);
    while (flag) {
        cv::Mat frame;
        capture >> frame;
        cv::Mat dst;
        cv::resize(frame, dst, cv::Size(x, y), 0, 0, 1);
        cv::imshow("view", dst);
        cv::waitKey(30);
    }
}


  1. 最后参考
    http://blog.csdn.net/zouxy09/article/details/8146266
    写一个button用来打开kinect,在这个基础上做了一些微小的改进,结合第2步的隐藏设置,直接可以在显示图片的框里显示kinect捕捉的2D视频,上面的连接里面对函数有非常详细的解释
    注意在工程中要引入Kinect的库文件
    这里写图片描述
    附加依赖:

opencv_ts300.lib
opencv_world300.lib
kernel32.lib
user32.lib
winspool.lib
comdlg32.lib
advapi32.lib
shell32.lib
ole32.lib
oleaut32.lib
uuid.lib
odbc32.lib
odbccp32.lib
Kinect10.lib

void CopentestDlg::OnBnClickedButton3()
{
    // TODO: 在此添加控件通知处理程序代码
    kinectable = true;
    cv::Mat image;
    image.create(480, 640, CV_8UC3);
    //1、初始化NUI   
    HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR);
    if (FAILED(hr))
    {
        AfxMessageBox(_T("打开kinect失败"));
        return ;
    }
    AfxMessageBox(_T("打开kinect成功"));
    //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);
    if (FAILED(hr))//判断是否提取正确   
    {
        AfxMessageBox(_T("读取错误"));
        NuiShutdown();
        return ;
    }
    //cv::namedWindow("colorImage", CV_WINDOW_AUTOSIZE);
    CRect rect;
    CWnd *pWnd = GetDlgItem(IDC_STATIC);
    pWnd->GetClientRect(&rect); //获取控件大小
    int x = rect.Width();
    int y = rect.Height();
    //4、开始读取彩色图数据   
    while (kinectable)
    {
        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);
                cv::waitKey(30);
                //imshow("colorImage", dst); //显示图像   
            }
            else
            {
                AfxMessageBox(_T("获取数据无效"));
            }

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

大概结果是这样的
这里写图片描述

最后

也没什么干货,就是把找资料过程中一些比较好的教程做了个总结。但是程序写完奇怪的是kinect摄像头和自带摄像头并不能一起调用。

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值