美文网首页OpenCV实战OpenCV与深度学习
MFC与OpenCV联合打开摄像头

MFC与OpenCV联合打开摄像头

作者: 冰不语 | 来源:发表于2017-04-02 17:48 被阅读329次

    opencv在图像处理和计算机视觉算法方面无疑是非常强大的,但是其GUI界面却是差强人意。当然原因很简单,这不是OpenCV开发人员关注的重点,他们只需要关注算法的实现和优化就行了。GUI方面自有其他的库来代替。

    我在之前也曾去学习过MFC和Qt,但都是浅尝辄止,主要原因是:一、它们的学习周期没那么短,不能很快地和OpenCV结合编出程序;二、自己的时间不由自己支配,总是有很多与此无关的任务。所幸,最近的任务需要用到MFC,于是终于有了略显深入的学习。

    然而学习了MFC之后,第一个任务仍然是当初学习opencv时的第一个任务——打开一张图片。好吧,虽然听起来很简单,但是真正实现起来确实费了很大一番劲。具体的难处还是随着叙述慢慢展现吧。由于这是《OpenCV实践之路》系列的博客,所以对于其中的MFC的细节可能就不做太过深入的讨论了。仍然是以OpenCV的内容为主。

    一、打开文件夹
    单纯用opencv都是直接打开一张图片,如果要打开另一张图片还要更改路径或者文件名,比较麻烦。有了界面的好处就是可以直接打开文件夹选择一张图片打开。MFC里打开文件夹获取文件名的程序如下:

    CString strFilter = _T("所有文件(*.*)|*.*|");
        CFileDialog dlg(TRUE, NULL, NULL, NULL, strFilter, this);
        if (!dlg.DoModal() == IDOK)
            return;
        CString strFileName = dlg.GetPathName();
        CFileStatus status;
        if (!CFile::GetStatus(strFileName, status))
        {
            MessageBox(strFileName + "不存在", L"信息提示", MB_OK);
            return;
        }
    

    这里偷了个懒,直接把文件过滤器写成了所有文件,主要是嫌把各种图片格式列出来太麻烦。而且这里这样也够了,自己打开的肯定是图片文件夹。最后的错误提示,在打开了对话框但是没有选择图片又把对话框关掉的时候会弹出。

    二、Mat和CImage相互转换
    对怎么在MFC中用OpenCV,各路大神各显神通,有用cvvimage.h和cvvimage.cpp的,也有其他的。我试用了很多种很多次,最后发现这个最好用。可以直接调用函数实现CImage和Mat的相互转换。感谢这位大神提供的方法。实现方式链接在这里:Mat和CImage相互转换
    我把这个类命名为MatCImage。Mat和CImage的转换可以用下面来那个函数实现,真的超简单实用:

    void MatCImage::MatToCImage(Mat& mat, CImage& cimage)
    void MatCImage::CImageToMat(CImage& cimage, Mat& mat)
    

    三、图片适应控件大小
    这里用cv::resize()函数来改变图片大小。当然也可以让控件适应图片大小。看自己选择。这个例子是图片适应控件。很简单,直接上代码:

    //加载图片到CImage
        CImage image;
        image.Load(strFileName);
    
        //把CImage转化为Mat
        MatCImage MatCImage;
        MatCImage.CImageToMat(image, img);
    
        //获取图片宽高比
        aspect_ratio = img.rows / img.cols;
        if (!img.empty())
        {
            get_image = true;
        }
    
        //获取图片控件的大小
        GetDlgItem(IDC_STATIC)->GetClientRect(&pic_rect);
        width = pic_rect.right;
        height = pic_rect.bottom;
    
        //改变图片大小适应picture控件
        resize(img, scaledImage, Size(width, height));
    
        //Mat转换为CImage
        if (!scaledImage.empty())
        {
            MatCImage.MatToCImage(scaledImage, img1);
        }
    

    四、图片的显示
    以上代码都是按钮的处理函数里面的。而图片的显示是在OnPaint()函数里面。代码如下:

        else
        {   
            if (!img1.IsNull())
            {
                //显示CImage图片
                img_show = img1;
                CWnd *pWnd = GetDlgItem(IDC_STATIC);//获得pictrue控件窗口的句柄   
                CDC *pDC = pWnd->GetDC();//获得pictrue控件的DC  
                if (!img_show.IsNull())
                {
                    img_show.Draw(pDC->m_hDC, pic_rect); //将图片画到Picture控件表示的矩形区域    
                }
    
                ReleaseDC(pDC);//释放picture控件的DC  
            }
    
            //不注释掉下面这一句会出现残留等很多问题
            //CDialogEx::OnPaint();  
        }
    

    强调,虽然已经写在注释里面了。最后一行一定要注释掉。不然问题很多,比如改变大小之后原来图片还在那里,会有叠加等各种问题。
    五、控件大小适应对话框
    也就是处理WM_SIZE消息:

    void CMFCImageDlg::OnSize(UINT nType, int cx, int cy)
    {
        CDialogEx::OnSize(nType, cx, cy);
    
        // TODO: Add your message handler code here
        GetClientRect(&dlg_rect);
        GetDlgItem(IDC_BUTTON1)->GetClientRect(&btn_rect);
        GetDlgItem(IDC_STATIC)->GetClientRect(&pic_rect);
    
        //设置按钮的位置
        btn_rect.MoveToX(dlg_rect.right - 100);
        btn_rect.MoveToY(dlg_rect.top + 100);
    
        //设置图片控价的大小
        if (get_image == true)
        {
            pic_rect.right = 3 * dlg_rect.Width() / 4;
            pic_rect.bottom = pic_rect.right * aspect_ratio;
        }
        else
        {
            pic_rect.right = 3 * dlg_rect.Width() / 4;
            pic_rect.bottom = dlg_rect.Height();
        }
    
        GetDlgItem(IDC_STATIC)->MoveWindow(pic_rect);
        GetDlgItem(IDC_BUTTON1)->MoveWindow(btn_rect);
    }
    

    五、效果
    界面很简陋,凑合着看,以后一定越来越好。

    最近开通了微信公众号,感兴趣的同学可以扫码在微信上交流。
    

    相关文章

      网友评论

      本文标题:MFC与OpenCV联合打开摄像头

      本文链接:https://www.haomeiwen.com/subject/ydvgottx.html