OpenCV实践之路——opencv与MFC强强联合打开图片

55 篇文章 205 订阅
45 篇文章 6 订阅

本文由@星沉阁冰不语出品,转载请注明作者和出处。
文章链接:http://blog.csdn.net/xingchenbingbuyu/article/details/51348394
微博:http://weibo.com/xingchenbing

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);
}

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

这里写图片描述

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

这里写图片描述

  • 9
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 26
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值