现在的位置: 首页 > 综合 > 正文

vs2010+mfc+Opencv2.4.9图片并显示

2018年05月18日 ⁄ 综合 ⁄ 共 2569字 ⁄ 字号 评论关闭

因为一些乱七八糟的原因。。。要把mfc和opencv结合起来使用。。于是有了这篇博客。。

本文亮点在于,无论是IplImage还是Mat格式的图像,咱都能显示。。。。

默认vs安装好,opencv+vs配置好,新建mfc基于对话框程序。。。

第一件事加两个文件CvvImage.h,CvvImage.cpp,因为opencv2.2之后这两个被抛弃了。。。所以咱得手动加回来

如图:

然后在项目头文件下,本文是Opencv_mfcDlg.h中添加头文件:

#include "CvvImage.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

然后同样在这个头文件下 COpencv_mfcDlg 对话框类下即:class COpencv_mfcDlg : public CDialogEx{}下添加显示mat的函数声明:

int ShowMat(cv::Mat img, HWND hWndDisplay);//显示Mat

然后在Opencv_mfcDlg.cpp下实现这个函数:

int COpencv_mfcDlg::ShowMat(cv::Mat img, HWND hWndDisplay) 
{ 
	if (img.channels()<3 ) { return -1; } 
	//构造将要显示的Mat版本图片 
	RECT rect; 
	::GetClientRect(hWndDisplay, &rect); 
	cv::Mat imgShow( abs(rect.top - rect.bottom), abs(rect.right - rect.left), CV_8UC3 ); 
	resize( img, imgShow, imgShow.size() ); 
	//在控件上显示要用到的CImage类图片 
	ATL::CImage CI; 
	int w=imgShow.cols;//宽 
	int h=imgShow.rows;//高 
	int channels=imgShow.channels();//通道数 
	CI.Create( w, h, 8*channels); //CI像素的复制 
	uchar *pS; uchar *pImg=(uchar *)CI.GetBits();//得到CImage数据区地址 
	int step=CI.GetPitch(); 
	for(int i=0;i<h;i++) 
	{ 
		pS=imgShow.ptr<uchar>(i);
		for(int j=0;j<w;j++) 
		{ 
			for(int k=0;k<3;k++) 
				*(pImg+i*step+j*3+k)=pS[j*3+k]; //注意到这里的step不用乘以3 
		} 
	} 
	//在控件显示图片 
	HDC dc ; 
	dc = ::GetDC(hWndDisplay); 
	CI.Draw( dc, 0, 0 ); 
	::ReleaseDC( hWndDisplay, dc); 
	CI.Destroy(); 
	return 0; 
}

然后搞个控件函数打开图像文件并调用上面的函数显示图像:

void COpencv_mfcDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	CString FilePath; 
	CFileDialog FileDlg(TRUE); 
	if (IDOK == FileDlg.DoModal()) 
	{ 
		//获取FileOpen对话框返回的路径名
		FilePath = FileDlg.GetPathName(); 
		//GetPathName返回的是CString类型,要经过转换为string类型才能使用imread打开图片 
		std::string	pathName(FilePath.GetBuffer()); 
		//读取图片 
		cv::Mat orgImg = cv::imread(pathName); 
		//显示图片 
		ShowMat(orgImg, GetDlgItem(IDC_STATIC)->GetSafeHwnd());
	}
}

上面步骤主要针对Mat图像的显示。。

效果如图:

那么问题来了,IplImage怎么办?有些情况下还是要用的。。例如,上任遗留代码。。何况,用mfc有几个不是因为上任对吧。。。。

其实之前添加的两个文件CvvImage.h,CvvImage.cpp就是为了这个作用。。。嗯,同样步骤,在头文件中添加显示函数声明

void DrawPicToHDC(IplImage *img, UINT ID);//显示IplImage

然后在实现文件添加实现:

void COpencv_mfcDlg::DrawPicToHDC(IplImage *img, UINT ID)
{
	CDC *pDC = GetDlgItem(ID)->GetDC();
	HDC hDC= pDC->GetSafeHdc();
	CRect rect;
	GetDlgItem(ID)->GetClientRect(&rect);
	CvvImage cimg;
	cimg.CopyOf( img ); // 复制图片
	cimg.DrawToHDC( hDC, &rect ); // 将图片绘制到显示控件的指定区域内
	ReleaseDC( pDC );
}

然后我咱改改OpenImg按键的代码。。

void COpencv_mfcDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	CString FilePath; 
	CFileDialog FileDlg(TRUE); 
	if (IDOK == FileDlg.DoModal()) 
	{ 
		//获取FileOpen对话框返回的路径名
		FilePath = FileDlg.GetPathName(); 
		//GetPathName返回的是CString类型,要经过转换为string类型才能使用imread打开图片 
		std::string	pathName(FilePath.GetBuffer()); 
		//读取图片 
		cv::Mat orgImg = cv::imread(pathName); 
		//显示图片 
		IplImage * img = &IplImage(orgImg);
		DrawPicToHDC(img,IDC_STATIC);
		//ShowMat(orgImg, GetDlgItem(IDC_STATIC)->GetSafeHwnd());
	}

其实就是将Mat转为IplImage,然后调用显示Iplmage的函数。。。

【上篇】
【下篇】

抱歉!评论已关闭.