第六章 KinectV2结合MFC显示和处理图像数据(上)

第六章   KinectV2结合MFC显示和处理图像数据(上)

 

首先声明一下,本系统所使用的开发环境版本是计算机系统Windows 10、Visual Studio 2013、Opencv3.0和Kinect SDK v2.0。这些都可以在百度上找到,download下来安装一下即可。详情参考本系列第二篇KinectV2结合opencv入门开发以及一些相关的学习资料

其实只要用前面几章的知识就差不多可以把基本功能实现了,只不过实在控制台下,没有一个好用的交互界面,不方便使用,更不能发挥Kinect的体感方面的优势。想到前面的基础程序是在C++基础上写的,故选了一个好入门的平台--MFC,说好入门不是说MFC简单,只是因为MFC比较成熟,学习资料较多,如果前面是在C#基础上写的,那肯定首选WPF了。MFC那么多内容,这里不便说清楚,我也说不清楚,只能大概说一下本系统的简单界面。

 

一、用电脑的摄像头代替Kinect的程序

 

核心的代码如下:

 

VideoCapture capture;	//定义一个摄像头类型的对象
 capture.open(0);	//打开摄像头
//AfxMessageBox("OK");
if (!capture.isOpened())	//判断是否打开摄像头
{
MessageBox(_T("无法打开摄像头"));
return;
}
//保存视频
writer = cvCreateVideoWriter("MyVideo.avi", CV_FOURCC('x', 'v', 'I', 'D'), 25, cvSize(640, 480));
// 测试
//IplImage* m_Frame;
Mat cframe;	//定义一个Mat类对象,用来存放摄像头的图像流
capture >> cframe;
IplImage* iframe;
iframe = &IplImage(cframe);	//Mat转IplImage
DrawPicToHDC(iframe, IDC_PIC_STATIC);	//显示摄像头获取的图像
//cvWaitKey(10);
 
// 设置计时器,每10ms触发一次事件
SetTimer(1, 10, NULL);

 

运行截图:

 

这是一个非简单的小demo,实现了普通相机的功能,就是录像和拍照啊之类的,基于MFC平台写的,非常简单,而且有详细注释,这里就不做过多的解释。这里给出整个过程的下载地址:

http://download.csdn.net/detail/baolinq/9618271

 

二、基于MFC平台的Kinect程序

 

有了上部分的基础,电脑摄像头和Kinect都是一种摄像头,只是Kinect相机更高端一点,是RGBD相机,很容易类比过去,把电脑摄像头换成kinect相机就差不多了。说起来是这么简单,一两句话的事,但这只是一种思想,如果真的用程序去实现还是有一定的难度。一起来看一下。

 

2.1 MFC 一个类访问另一个类成员对象的成员变量值 

 

电脑摄像头比较简单,只有几句话就可以表达出来,可以直接写在MFC自动生成的类和方法里面,然后单击按钮触发事件。但是Kinect的初始化和启动以及获取图像的程序那么长,如果也放在那下面的话,会显得程序结构很乱,可读性很差。一般我们会自己创建类和自己的方法,然后在MFC自带的类和方法里面调用自己创建的类,这样可以一目了然,程序干净整洁,也更加便于维护。这里就会遇到MFC里面一个类访问另一个类成员对象的成员变量值 。

 

 

MFC中一个类要访问另外一个类的的对象的成员变量值,这就需要获得原来那个类对象的指针,其实有好几种方法都可以实现。

比如维护一个单例模式、设置静态变量等等。我们这里举个列子,实现多个类之间的相互访问。

 

1示例:创建MFC对话框,实现对个对话框之间数据访问

1. 我们创建一个MFC对话框应用程序,命名为Visit工程.

2. 对话框本身有一个主界面(CVisitDlg对话框),那我们再添加一个新界面CXXXDlg.

2在主界面CVisitDlg类的头文件中,添加一个static CVisitDlg *s_pDialog;指针(注:添加为共有类型的)

由于这个指针式静态的,我们需要在类外初始化,那么我们在CVisitDlg .cpp文件中,写上一行初始化代码,直接初始化为空,如下:

CVisitDlg *CVisitDlg::s_pDialog = NULL; //(注意要写在类外,不要写在类实现函数里面)。

3然后需要在CVisitDlg 主对话框生成的时候,给这个指针赋值为主对话框指针。

那么,我们可以在CVisitDlg 类的构造函数或者OnInitDialog()函数里面写上如下一句代码:

s_pDialog = this;

好了,现在我们只要在其他的类里面获得这个静态指针,就可以访问这个类里面的所有数据了~~~~

4获得静态指针

假设,我们想在CXXXDlg类中访问CVisitDlg类的数据,如下代码轻轻松松搞定:

CVisitDlg *pDia = CVisitDlg::s_pDialog;

 

小插曲:这里推荐一个学习编程的网站   鸡啄米http://www.jizhuomi.com/software/257.html,

里面有MFC的入门学习资料,很基础,可以快速入门,想提高的话,可以看孙鑫老师的VC++和深入浅出MFC之类的。

 

2.2  MFC创建文件夹

就是在指定目录下创建文件夹,然后把一些处理结果和图片保存到该目录下。


CString m_strFolderPath=_T("E:\\path");
if(!PathIsDirectory(m_strFolderPath))
{
CString strMsg;
strMsg.Format (_T("指定路径\"%s\"不存在,是否创建?"), m_strFolderPath); 
if (AfxMessageBox(strMsg, MB_YESNO) == IDYES)
{
if (!CreateDirectory(m_strFolderPath, NULL ) ) 
{
strMsg.Format(_T("创建路径\"%s\"失败!是否继续?"), m_strFolderPath); 
if (AfxMessageBox(strMsg, MB_YESNO) == IDYES) 
return; 
}
}
}


但是此处CreateDirectory有局限性,只能创建单层文件夹,如果需要创建多层,还需要自己写函数

 

2.3  MFC窗口背景颜色和控件颜色的设置

如果只是像前面那个例子那样,整个界面全是灰色的,那界面就很没意思了,太难看了,没人愿意去使用这样的东西。既然做了界面,就应该做的酷炫一点,美观一点,这样用起来才会比较愉悦。这里给大家讲一些最简单的装X利器,给背景和控件上点颜色,这样简单的步骤会让你的界面看起来比较高端~~

对话框背景色的设置

参考:http://www.tuicool.com/articles/miai6f

(1)重载OnPaint()函数,即WM_PAINT消息,代码如下所示:

void CtestDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文
 
        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
 
        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;
 
        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        //CDialogEx::OnPaint();
 
        //设置为绿色背景
        CRect   rect; 
        CPaintDC   dc(this); 
        GetClientRect(rect); 
        dc.FillSolidRect(rect,RGB(0,255,0));  
    }
}
 


2、重载OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor),即WM_CTLCOLOR消息:

 a)在对话框的.h文件中添加CBrush类的成员m_brush

  b)在对话框的.cpp文件中的OnInitDialog()中添加以下代码(背景红色):

<span style="white-space: pre;">	</span>m_brush.CreateSolidBrush(RGB(255,0,0));
  
c)重载OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor),代码如下:

 
HBRUSH CtestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
 
    // TODO:  在此更改 DC 的任何特性
    
    if(nCtlColor == CTLCOLOR_DLG) 
        return   m_brush;   //返加红色刷子  
    
    // TODO:  如果默认的不是所需画笔,则返回另一个画笔
    return hbr;<pre name="code" class="cpp">


控件颜色的设置

重载OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor),即WM_CTLCOLOR消息:

HBRUSH CtestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
 
    // TODO:  在此更改 DC 的任何特性
 
    // 设置显示字体
    CFont * font=new CFont;
    font->CreateFont(16,0,0,0,FW_SEMIBOLD,FALSE,FALSE,0,
        ANSI_CHARSET,OUT_DEFAULT_PRECIS,
        CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
        DEFAULT_PITCH&FF_SWISS,_T("Arial"));
 
    switch(nCtlColor)
    {
    case CTLCOLOR_STATIC: //对所有静态文本框的设置        {
            pDC->SetBkMode(TRANSPARENT);
            //设置背景为透明
            pDC->SetTextColor(RGB(255,255,0)); //设置字体颜色
            pWnd->SetFont(font); //设置字体
            HBRUSH B = CreateSolidBrush(RGB(125,125,255));
            //创建画刷
            return (HBRUSH) B; //返回画刷句柄        }
    case CTLCOLOR_EDIT: //对所有编辑框的设置        {
            if(IDC_EDIT2 == pWnd->GetDlgCtrlID())
            {
                pDC->SetBkMode(TRANSPARENT);
                pDC->SetTextColor(RGB(255,255,0));
                pWnd->SetFont(font);
                HBRUSH B = CreateSolidBrush(RGB(125,125,125));
                return (HBRUSH) B;
            }
            if(IDC_EDIT3 == pWnd->GetDlgCtrlID())
            {
                pDC->SetBkMode(TRANSPARENT);
                pDC->SetTextColor(RGB(255,0, 0));
                pWnd->SetFont(font);
                HBRUSH B = CreateSolidBrush(RGB(125,125,0));
                return (HBRUSH) B;
            }
        }
    default:
        return CDialog::OnCtlColor(pDC,pWnd, nCtlColor);
    }
 
    // TODO:  如果默认的不是所需画笔,则返回另一个画笔
    return hbr;
}


注:

nCtlColor的类别有以下几种:

CTLCOLOR_BTN  按钮控件

CTLCOLOR_DLG  对话框

CTLCOLOR_EDIT  编辑框

CTLCOLOR_LISTBOX  列表框

CTLCOLOR_MSGBOX   消息框

CTLCOLOR_SCROLLBAR  滚动条

CTLCOLOR_STATIC  静态文本

 

这部分主要给大家讲了一下MFC做界面遇到的部分困难,不会的时候他们是困难,学会了之后就是技术了。还有一些其他常见的问题比如界面的放大缩小、最大化和还原、界面的多线程问题等等,还有好多的。通过这些就可以很容易做出类似这样的界面

 

 

类比第一个程序,把Kinect代替电脑的摄像头,然后把Kinect 获取的图像显示到MFC界面上,这个问题的主要难度都在文章的第二部分讲到了,并给出了解决方案,具体的实现将在下一章中讲解。敬请期待~

 

超跑开起来,要先制定一个小目标,比如先买辆兰博基尼限量款~哈哈哈得意得意得意

 

 

 

 

展开阅读全文

没有更多推荐了,返回首页