在前面我们已经完成VS2022下安装和配置OpenCV环境参数下面我们开始小试身手,试试OpenCV读取图片到Picture Control中。网上的资料大多是基于C++控制台的,少有MFC桌面应用程序的。这里整理了三段代码,作为第一次的笔记。
分别是:MFC中对话框读取图片、OpenCV自适应绘图、OpenCV载入图片。
我们的场景如下图:左边是个Picture Control,右边是个Button,目标是通过Button来打开资源管理器对话框,选中图片,通过OpenCV载入到左边的Picture Control并将图片自适应展示。
第一步:打开资源管理器对话框,选择图片文件,返回文件路径以备用
CString CmyMFCDlg::fun_LoadImg()
{
// TODO: 在此添加命令处理程序代码
CString imagePath = L"";//选择的图片全路径
BOOL isOpen = TRUE; //是否打开(否则为保存)
CString defaultDir = L"E:\\"; //默认打开的文件路径
CString fileName = L""; //默认打开的文件名
CString filter = L"文件 (*.bmp; *.jpg;*.png)|*.bmp;*.jpg;*.png||"; //文件过虑的类型
CFileDialog openFileDlg(isOpen, NULL, defaultDir + fileName, OFN_HIDEREADONLY | OFN_READONLY, filter, NULL);
if (openFileDlg.DoModal() == IDOK)
{
imagePath = openFileDlg.GetPathName();
}
return imagePath;
}
第二步:OpenCV自适应绘图
#include "opencv2/opencv.hpp"
#include
using namespace cv;
……
//参数1:opencv即将读的图,
//参数2:需要展示的Picture Control的ID
void CmyMFCDlg::DrawMat(cv::Mat& img, UINT nID)
{
cv::Mat imgTmp;
CRect rect;
GetDlgItem(nID)->GetClientRect(&rect); // 获取控件大小
cv::resize(img, imgTmp, cv::Size(rect.Width(), rect.Height()));// 缩放Mat并备份
// 转一下格式 ,这段可以放外面,
switch (imgTmp.channels())
{
case 1:
cv::cvtColor(imgTmp, imgTmp, CV_GRAY2BGRA); // GRAY单通道
break;
case 3:
cv::cvtColor(imgTmp, imgTmp, CV_BGR2BGRA); // BGR三通道
break;
default:
break;
}
int pixelBytes = imgTmp.channels() * (imgTmp.depth() + 1); // 计算一个像素多少个字节
// 制作bitmapinfo(数据头)
BITMAPINFO bitInfo;
bitInfo.bmiHeader.biBitCount = 8 * pixelBytes;
bitInfo.bmiHeader.biWidth = imgTmp.cols;
bitInfo.bmiHeader.biHeight = -imgTmp.rows;
bitInfo.bmiHeader.biPlanes = 1;
bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitInfo.bmiHeader.biCompression = BI_RGB;
bitInfo.bmiHeader.biClrImportant = 0;
bitInfo.bmiHeader.biClrUsed = 0;
bitInfo.bmiHeader.biSizeImage = 0;
bitInfo.bmiHeader.biXPelsPerMeter = 0;
bitInfo.bmiHeader.biYPelsPerMeter = 0;
// Mat.data + bitmap数据头 -> MFC
CDC* pDC = GetDlgItem(nID)->GetDC();
::StretchDIBits(
pDC->GetSafeHdc(),
0, 0, rect.Width(), rect.Height(),
0, 0, rect.Width(), rect.Height(),
imgTmp.data,
&bitInfo,
DIB_RGB_COLORS,
SRCCOPY
);
ReleaseDC(pDC);
}
//.h文件
#include "opencv2/opencv.hpp"
……
public:
CString fun_LoadImg();//第一步
void DrawMat(cv::Mat& img, UINT nID);//第二步
afx_msg void OnBnClickedTest(); //第三步
第三步:展示OpenCV的图片
//button按钮响应事件
void CmyMFCDlg::OnBnClickedTest()
{
USES_CONVERSION;//和下一行的W2A的目的一样,是为了CString类型转const String
Mat src = imread(W2A(fun_LoadImg()), 1);
DrawMat(src, IDC_STATIC);
}
我们编译下看看效果: