【18】MFC入门到精通——MFC(VS2019)+ OpenCV 显示图片的3种方法

MFC (VS2019)+ OpenCV,显示图片的3种方法

1 方法介绍
2 方法一:嵌套OpenCV窗口显示图片

2.1 建立供工程 添加控件
2.2 引用头文件
2.3 找到OnInitDialog()函数,在其中添加如下代码
2.4 在button触发函数中加入代码(就是你双击button进入的函数)
2.5 注意事项

3 方法二: 转换图片格式

3.1 MatToCImage格式转换 定义
3.2 OnPaint() 添加代码 画出图像

4 方法三: OpenCV图片保存后,再用FMC读取显示

4.1 添加代码
4.2 为什么要先保存在读取呢?

1 方法介绍

1、嵌套。 直接将OpenCV窗口嵌套到MFC的Pictrue Control控件中。此方法既能直接显示图片,也可直接使用OpenCV的鼠标按键事件,但对于鼠标滚轮事件只能使用MFC本地的滚轮函数。

2、转换。 将OpenCV读取或处理的图片转换格式,使之成为MFC的Pictrue Control控件可显示的图片格式。此方法每刷新一次图片便需要转换格式一次,比较麻烦,且只能使用MFC的鼠标事件。

3、保存。 将OpenCV读取或处理的图片保存为本地图片,然后用MFC读取图片的方法读取并显示。此方法是笨方法,在特定情况下使用,保存和读取图片比较耗时,但无需转换格式,同样只能使用MFC的鼠标事件。

2 方法一:嵌套OpenCV窗口显示图片

嵌套。直接将OpenCV窗口嵌套到MFC的Pictrue Control控件中。此方法既能直接显示图片,也可直接使用OpenCV的鼠标按键事件,但对于鼠标滚轮事件只能使用MFC本地的滚轮函数。

2.1 建立供工程 添加控件

新建工程,命名为 showRealVideo,创建好之后,自动生成以下文件

打开对话框后,
在工具箱选择picture control控件,并拖到对话框内,(右键修改属性),修改ID为IDC_PICTURE_STATIC
添加一个Button按钮,修改ID为IDC_PICTURE_BUTTON,描述文字为 “显示图像”

双击button (“显示图像”)按钮,之后可以进入****Dlg.cpp,在里面进行如下修改代码

编写代码,只需修改MFCApplication1Dlg.cpp文件。

具体修改步骤如下:

2.2 引用头文件

在showRealVideoDlg.cpp中 添加opencv头文件

#include <opencv2/opencv.hpp>
//cvGetWindowHandle("ImageShow");//嵌套opencv窗口,需要使用下面头文件
#include<opencv2/highgui/highgui_c.h>

2.3 找到OnInitDialog()函数,在其中添加如下代码

// TODO: 在此添加额外的初始化代码

	cv::namedWindow("ImageShow");//创建OpenCV窗口
	HWND  hWnd = (HWND)cvGetWindowHandle("ImageShow");//嵌套opencv窗口
	HWND hParent = ::GetParent(hWnd);
	::SetParent(hWnd,GetDlgItem(IDC_PICTURE_STATIC)->m_hWnd);
	::ShowWindow(hParent,SW_HIDE);

2.4 在button触发函数中加入代码(就是你双击button进入的函数)

void CshowRealVideoDlg::OnBnClickedPictureButton()
{
	// TODO: 在此添加控件通知处理程序代码
	cv::Mat img = cv::imread("D:\Projects\test_Images\9.jpg");
	CRect rect;
	CWnd* pWnd = GetDlgItem(IDC_PICTURE_STATIC);//获取picture control控件

	pWnd->GetClientRect(&rect);//控制图片的大小
	cv::resize(img, img, cv::Size(rect.Width(), rect.Height()));//将图片resize,适用窗口尺寸

	imshow("ImageShow", img);

}

图片[1] - 【18】MFC入门到精通——MFC(VS2019)+ OpenCV 显示图片的3种方法 - 宋马

2.5 注意事项

如果图片没有resize,那么图片将以原尺寸显示,不会自适应窗口大小;

超出窗口以外的尺寸,就不会显示。

void CshowRealVideoDlg::OnBnClickedPictureButton()
{
	// TODO: 在此添加控件通知处理程序代码
	
	cv::Mat img = cv::imread("D:\Projects\test_Images\9.jpg");
	CWnd* pWnd = GetDlgItem(IDC_PICTURE_STATIC);//获取picture control控件
	imshow("ImageShow",img);
}

也可以将代码全部写在Button按钮函数中,
即将OnInitDialog()函数中自己添加的代码,剪切到OnBnClickedPictureButton()函数里。

3 方法二: 转换图片格式

转换。 将OpenCV读取或处理的图片转换格式,使之成为MFC的Pictrue Control控件可显示的图片格式。此方法每刷新一次图片便需要转换格式一次,比较麻烦,且只能使用MFC的鼠标事件。

1、新建MFC应用程序、添加Pictrue Control控件(同上)

2、引用头文件

在showRealVideoDlg.cpp中 添加opencv头文件,
并声明函数 void MatToCImage(Mat &mat, CImage &cImage);

#include <opencv2/opencv.hpp>

	void MatToCImage(cv::Mat& mat, CImage& cImage);

3.1 MatToCImage格式转换 定义

//在CshowRealVideoDlg::.cpp最后添加MatToCImage函数定义:

//将OpenCV处理的Mat图片格式 转换为MFC的Pictrue Control控件可显示的CImage格式
void CshowRealVideoDlg::MatToCImage(cv::Mat& mat, CImage& cImage)
{
            
	//create new CImage
	int width = mat.cols;
	int height = mat.rows;
	int channels = mat.channels();

	cImage.Destroy(); //clear
	cImage.Create(width, height, 8 * channels); //默认图像像素单通道占用1个字节

	//copy values
	uchar* ps;
	uchar* pimg = (uchar*)cImage.GetBits(); //A pointer to the bitmap buffer 指向位图缓冲区的指针
	int step = cImage.GetPitch();

	for (int i = 0; i < height; ++i)
	{
            
		ps = (mat.ptr<uchar>(i));
		for (int j = 0; j < width; ++j)
		{
            
			if (channels == 1) //gray
			{
            
				*(pimg + i * step + j) = ps[j];
			}

			else if (channels == 3) //color
			{
            
				for (int k = 0; k < 3; ++k)
				{
            
					*(pimg + i * step + j * 3 + k) = ps[j * 3 + k];
				}
			}
		}
	}
}

3.2 OnPaint() 添加代码 画出图像

CshowRealVideoDlg::OnPaint()添加以下代码 画出图像

//////添加用户自己的代码
	UpdateWindow();//刷新窗口

	cv::Mat matImg = cv::imread("D:\Projects\test_Images\9.jpg"); //opencv读取图片

	CRect rect;//定义矩形类
	CWnd* pWnd = GetDlgItem(IDC_PICTURE_STATIC);//获取控件句柄
	pWnd->GetClientRect(&rect); //获取句柄指向控件区域的大小
	CDC* pDc = pWnd->GetDC();//获取picture的DC

	cv::Mat resizedImg;
	int win_w = rect.Width(), win_h = rect.Height();//获取窗口宽高
	cv::resize(matImg, resizedImg, cv::Size(win_w, win_h));//将图片resize,适用窗口尺寸
	int img_w = resizedImg.cols, img_h = resizedImg.rows;//获取图片宽高

	CImage ImageCam;
	MatToCImage(resizedImg, ImageCam);//转换图片格式

	pDc->SetStretchBltMode(COLORONCOLOR);
	ImageCam.Draw(pDc->m_hDC, 0, 0, win_w, win_h, 0, 0, img_w, img_h);//画出图片
	ReleaseDC(pDc);

运行直接显示图片
图片[2] - 【18】MFC入门到精通——MFC(VS2019)+ OpenCV 显示图片的3种方法 - 宋马
如果要使用,点击按钮 ,显示图片,
将上面OnPaint()里面添加的代码,复制到OnBnClickedPictureButton()函数里。
(OnPaint()里面添加的代码 删除或注释掉)
图片[3] - 【18】MFC入门到精通——MFC(VS2019)+ OpenCV 显示图片的3种方法 - 宋马
图片[4] - 【18】MFC入门到精通——MFC(VS2019)+ OpenCV 显示图片的3种方法 - 宋马

4 方法三: OpenCV图片保存后,再用FMC读取显示

保存。 将OpenCV读取或处理的图片保存为本地图片,然后用MFC读取图片的方法读取并显示。此方法是笨方法,在特定情况下使用,保存和读取图片比较耗时,但无需转换格式,同样只能使用MFC的鼠标事件。

1、新建MFC应用程序、添加Pictrue Control控件(同上)

2、引用头文件

在showRealVideoDlg.cpp中 添加opencv头文件,

#include <opencv2/opencv.hpp>

4.1 添加代码

void CshowRealVideoDlg::OnBnClickedPictureButton()
{
            
	// TODO: 在此添加控件通知处理程序代码

	cv::Mat matImg = cv::imread("D:\Projects\test_Images\9.jpg");//opencv读取图片
	cv::imwrite("D:\Projects\test_Images\9_new.jpg", matImg);//保存opencv图片

	CImage img;
	img.Load(L"D:\Projects\test_Images\9_new.jpg");//mfc读取图片
	int img_w = img.GetWidth(), img_h = img.GetHeight();//获取图片宽高

	UpdateWindow();//刷新窗口

	CRect rect;//定义矩形类
	CWnd* pWnd = GetDlgItem(IDC_PICTURE_STATIC);//获取控件句柄
	pWnd->GetClientRect(&rect); //获取句柄指向控件区域的大小
	CDC* pDc = pWnd->GetDC();//获取picture的DC

	int win_w = rect.Width(), win_h = rect.Height();//获取窗口宽高
	pDc->SetStretchBltMode(COLORONCOLOR);
	img.Draw(pDc->m_hDC, 0, 0, win_w, win_h, 0, 0, win_w, win_h);//画出图片
	ReleaseDC(pDc);
}

(程序中没有写 resize,所以图片没有自适应窗口大小)

如果不需要按钮,直接显示,将上面代码剪切到 OnPaint()里面

4.2 为什么要先保存在读取呢?

为什么要先保存在读取呢? 看似多余,实则不然。

直接MFC读取,会报错

CImage img;
	img.Load(L"D:\Projects\test_Images\9.jpg");//mfc读取图片

图片[5] - 【18】MFC入门到精通——MFC(VS2019)+ OpenCV 显示图片的3种方法 - 宋马
将保存的图片 再次用OpenCV方式发打开显示,出错

cv::imwrite("D:\Projects\test_Images\9_new.jpg", matImg);//保存opencv图片

图片[6] - 【18】MFC入门到精通——MFC(VS2019)+ OpenCV 显示图片的3种方法 - 宋马
进一步查看,发现保存后的图片信息发生了变化,
图片[7] - 【18】MFC入门到精通——MFC(VS2019)+ OpenCV 显示图片的3种方法 - 宋马

【参考教程】

使用 MFC 和 OpenCV 实现实时摄像头视频显示
MFC(vs2013)+opencv+海康SDK_显示视频教程
VC++海康威视视频人数流量统计数据库连接
如何利用MFC及Opencv读入摄像头并显示画面

关于找不到cvGetWindowHandle()的解决方法

MFC+Opencv+显示图片的方法
MFC OpenCV,示图片的3种方法

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容