MFC OpenCV:显示图片的3种方法(详细)
一、背景
二、方法
三、实现
3.1 嵌套OpenCV窗口显示图片
3.2 转换格式显示OpenCV图片
3.3 OpenCV图片保存后显示
一、背景
由于OpenCV常用的界面只是单纯的打开图像窗口,相关界面控件和工具较少且不美观,故使用MFC制作界面,而用OpenCV单纯做图像处理。此时便需要在MFC中显示OpenCV所用的图片。
二、方法
1、嵌套。直接将OpenCV窗口嵌套到MFC的Pictrue Control控件中。此方法既能直接显示图片,也可直接使用OpenCV的鼠标按键事件,但对于鼠标滚轮事件只能使用MFC本地的滚轮函数。
2、转换。将OpenCV读取或处理的图片转换格式,使之成为MFC的Pictrue Control控件可显示的图片格式。此方法每刷新一次图片便需要转换格式一次,比较麻烦,且只能使用MFC的鼠标事件。
3、保存。将OpenCV读取或处理的图片保存为本地图片,然后用MFC读取图片的方法读取并显示。此方法是笨方法,在特定情况下使用,保存和读取图片比较耗时,但无需转换格式,同样只能使用MFC的鼠标事件。
三、实现
3.1 嵌套OpenCV窗口显示图片
1、新建MFC应用程序。
2、配置OpenCV运行环境。
3、添加MFC的Pictrue Control控件
4、编写代码。只需修改MFCApplication1Dlg.cpp文件。
添加的代码:
//在MFCApplication1Dlg.cpp添加库文件 #include "opencv2/opencv.hpp" using namespace cv; //在MFCApplication1Dlg.cpp的CMFCApplication1Dlg::OnInitDialog()函数中添加如下代码: // TODO: 在此添加额外的初始化代码 namedWindow("ImageShow");//创建OpenCV窗口 HWND hWnd = (HWND)cvGetWindowHandle("ImageShow");//嵌套opencv窗口 HWND hParent = ::GetParent(hWnd); ::SetParent(hWnd, GetDlgItem(IDC_STATIC)->m_hWnd); ::ShowWindow(hParent, SW_HIDE); Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片 imshow("ImageShow", mat);//opencv显示图片 waitKey(1);
全部代码:
// MFCApplication1Dlg.cpp: 实现文件 // #include "stdafx.h" #include "MFCApplication1.h" #include "MFCApplication1Dlg.h" #include "afxdialogex.h" #include "opencv2/opencv.hpp" using namespace cv; #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CMFCApplication1Dlg 对话框 CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() END_MESSAGE_MAP() // CMFCApplication1Dlg 消息处理程序 BOOL CMFCApplication1Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 namedWindow("ImageShow");//创建OpenCV窗口 HWND hWnd = (HWND)cvGetWindowHandle("ImageShow");//嵌套opencv窗口 HWND hParent = ::GetParent(hWnd); ::SetParent(hWnd, GetDlgItem(IDC_STATIC)->m_hWnd); ::ShowWindow(hParent, SW_HIDE); Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片 imshow("ImageShow", mat);//opencv显示图片 waitKey(1); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CMFCApplication1Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CMFCApplication1Dlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); }
5、运行结果
3.2 转换格式显示OpenCV图片
1、新建MFC应用程序(同上)
2、配置OpenCV环境(同上)
3、添加Pictrue Control控件(同上)
4、编写程序
添加的代码:
//在MFCApplication2Dlg.h添加库文件及函数声明 #include "opencv2/opencv.hpp" using namespace cv; void MatToCImage(Mat &mat, CImage &cImage); //在MFCApplication2Dlg.cpp最后添加函数定义: void MatToCImage(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]; } } } } } //在CMFCApplication2Dlg::OnPaint()画出图片: UpdateWindow();//刷新窗口 Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片 //resize(mImage, mImage, Size(), 0.3, 0.3); CRect rect;//定义矩形类 CWnd *pWnd = GetDlgItem(IDC_STATIC);//获取控件句柄 pWnd->GetClientRect(&rect); //获取句柄指向控件区域的大小 CDC *pDc = pWnd->GetDC();//获取picture的DC int win_w = rect.Width(), win_h = rect.Height();//获取窗口宽高 int img_w = mat.cols, img_h = mat.rows;//获取图片宽高 CImage ImageCam; MatToCImage(mat, ImageCam);//转换图片格式 pDc->SetStretchBltMode(COLORONCOLOR); ImageCam.Draw(pDc->m_hDC, 0, 0, win_w, win_h, 0, 0, win_w, win_h);//画出图片 ReleaseDC(pDc);
MFCApplication2Dlg.h全部代码:
// MFCApplication2Dlg.h: 头文件 // #pragma once #include "opencv2/opencv.hpp" using namespace cv; // CMFCApplication2Dlg 对话框 class CMFCApplication2Dlg : public CDialogEx { // 构造 public: CMFCApplication2Dlg(CWnd* pParent = nullptr); // 标准构造函数 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_MFCAPPLICATION2_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() }; void MatToCImage(Mat &mat, CImage &cImage);
MFCApplication2Dlg.cpp全部代码:
// MFCApplication2Dlg.cpp: 实现文件 // #include "stdafx.h" #include "MFCApplication2.h" #include "MFCApplication2Dlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CMFCApplication2Dlg 对话框 CMFCApplication2Dlg::CMFCApplication2Dlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_MFCAPPLICATION2_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMFCApplication2Dlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMFCApplication2Dlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() END_MESSAGE_MAP() // CMFCApplication2Dlg 消息处理程序 BOOL CMFCApplication2Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CMFCApplication2Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CMFCApplication2Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } UpdateWindow();//刷新窗口 Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片 //resize(mImage, mImage, Size(), 0.3, 0.3); CRect rect;//定义矩形类 CWnd *pWnd = GetDlgItem(IDC_STATIC);//获取控件句柄 pWnd->GetClientRect(&rect); //获取句柄指向控件区域的大小 CDC *pDc = pWnd->GetDC();//获取picture的DC int win_w = rect.Width(), win_h = rect.Height();//获取窗口宽高 int img_w = mat.cols, img_h = mat.rows;//获取图片宽高 CImage ImageCam; MatToCImage(mat, ImageCam);//转换图片格式 pDc->SetStretchBltMode(COLORONCOLOR); ImageCam.Draw(pDc->m_hDC, 0, 0, win_w, win_h, 0, 0, win_w, win_h);//画出图片 ReleaseDC(pDc); } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CMFCApplication2Dlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void MatToCImage(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]; } } } } }
5、运行结果
3.3 OpenCV图片保存后显示
1、新建MFC应用程序(同上)
2、配置OpenCV环境(同上)
3、添加Pictrue Control控件(同上)
4、编写程序
添加的代码:
//在CMFCApplication2Dlg添加库文件: #include "opencv2/opencv.hpp" using namespace cv; //在CMFCApplication2Dlg::OnPaint()画出图片: Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片 imwrite("E:\\vs\\image\\11_new.png", mat);//保存opencv图片 CImage img; img.Load(L"E:\\vs\\image\\11_new.png");//mfc读取图片 int img_w = img.GetWidth(), img_h = img.GetHeight();//获取图片宽高 UpdateWindow();//刷新窗口 CRect rect;//定义矩形类 CWnd *pWnd = GetDlgItem(IDC_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);
全部代码:
// MFCApplication3Dlg.cpp: 实现文件 // #include "stdafx.h" #include "MFCApplication3.h" #include "MFCApplication3Dlg.h" #include "afxdialogex.h" #include "opencv2/opencv.hpp" using namespace cv; #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CMFCApplication3Dlg 对话框 CMFCApplication3Dlg::CMFCApplication3Dlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_MFCAPPLICATION3_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMFCApplication3Dlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMFCApplication3Dlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() END_MESSAGE_MAP() // CMFCApplication3Dlg 消息处理程序 BOOL CMFCApplication3Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CMFCApplication3Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CMFCApplication3Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片 imwrite("E:\\vs\\image\\11_new.png", mat);//保存opencv图片 CImage img; img.Load(L"E:\\vs\\image\\11_new.png");//mfc读取图片 int img_w = img.GetWidth(), img_h = img.GetHeight();//获取图片宽高 UpdateWindow();//刷新窗口 CRect rect;//定义矩形类 CWnd *pWnd = GetDlgItem(IDC_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); } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CMFCApplication3Dlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); }
5、运行结果
————————————————
版权声明:本文为CSDN博主「扶摇直上九万里wyh」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34801642/article/details/89945082

