环境:VS2012,OpenCV 2.4.9
功能描述:
功能1:点击OPEN按钮,选择图片并打开,下方显示图片的信息;
功能2:把图片拖曳到OPEN按钮上,也可以实现打开功能,支持多文件同时打开
意义:MFC练手程序,涉及一些知识点
过程:
1、前期工作
建立MFC工程,命名“showPicture”,取消unicode,选择对话框,其它默认;
选择Release;
添加opencv的包含目录和库目录,添加依赖项。
2、对话框编辑
a.删除“TODO: 在此放置对话框控件。”控件,把“确认”和“取消”控件的“Visible”属性设为False;
b.添加Button控件,修改以下属性:
ID:IDC_BUTTON_OPEN
Acccept Files:True
Caption:OPEN
c.添加Group Box 控件,Caption属性改为information;
d.添加5个Static Text控件,Caption属性依次改为filename、format、depth、h、w;
e.每个Static Text控件对应添加一个Edit Contral控件,ID依次为IDC_EDIT_filename、IDC_EDIT_FORMAT、IDC_EDIT_DEPTH、IDC_EDIT_H、IDC_EDIT_W,全部的Read Only属性设为True,依次添加成员变量Edit_filename、Edit_format、Edit_depth、Edit_h、Edit_w
f.对文本框左对齐和顶端对齐
如图:
3、编码实现功能1
a.添加头文件image.h
#pragma once #pragma comment(lib,"opencv_highgui249.lib") #pragma comment(lib,"opencv_core249.lib") #pragma comment(lib,"opencv_imgproc249.lib") #include <opencv2/opencv.hpp> #define EPS 2.2204E-16 using namespace std; using namespace cv; class image { public: image(void); ~image(void); public: Mat img; };
b.为OPEN按钮添加事件处理程序OnBnClickedButtonOpen()
void CshowPictureDlg::OnBnClickedButtonOpen() { // TODO: 在此添加控件通知处理程序代码 CFileDialog fDlg(TRUE, _TEXT("*"), NULL, 4|2, _TEXT("全部文件(*.*)|*.*|全部文件(*.*)|*.*||")); // 调用 DoModal() 方法来打开对话框 if (fDlg.DoModal() == IDOK) { // 设置编辑框1的内容为选择文件的路径 // GetPathName() --> 返回选定文件的完整路径 CString path; path = fDlg.GetPathName(); if(!path.IsEmpty()) { img = imread((LPCSTR)path,CV_LOAD_IMAGE_ANYCOLOR); CString imageName; imageName = path; imageName.MakeReverse(); int index=imageName.Find('\\'); imageName = imageName.Left(index); imageName.MakeReverse(); //显示图像信息 CString info; info.Format("%d",img.rows); Edit_h.SetWindowText(info); info.Format("%d",img.cols); Edit_w.SetWindowText(info); int depth; switch(img.depth()) { case 0 :; case 1 :depth=8;break; case 2 :; case 3 :depth=16;break; } info.Format("%d",depth); Edit_depth.SetWindowText(info+"bits"); index = imageName.Find('.'); info = imageName.Right(imageName.GetLength()-index-1); Edit_format.SetWindowText(info); info = imageName; Edit_filename.SetWindowText(info); //显示图像 namedWindow((LPCSTR)imageName, CV_WINDOW_NORMAL); resizeWindow((LPCSTR)imageName,img.cols,img.rows); imshow((LPCSTR)imageName,img); } } }showPictureDlg.h中添加
#include "image.h"以及新增成员变量
private: Mat img;
4、编码实现功能2
在3的基础上继续;
a.用类向导添加一个MFC类,基类为CButton,类名为CFileButton,该类用于实现拖曳文件至OPEN按钮并打开的功能;
b.为CFileButton添加ON_WM_DROPFILES消息,并编辑消息函数
// CFileButton 消息处理程序 void CFileButton::OnDropFiles(HDROP hDropInfo) { // TODO: 在此添加消息处理程序代码和/或调用默认值 destroyAllWindows(); char *lpszFileName=new char[512]; int nFileCount,i; nFileCount=::DragQueryFile (hDropInfo,0xFFFFFFFF,NULL,512); CString path; UINT nChars; Mat img; for (i=0;i < nFileCount;i++) { nChars=::DragQueryFile (hDropInfo,i,&lpszFileName[0],512); path = lpszFileName; path = path.Left(nChars); if(!path.IsEmpty()) { img = imread((LPCSTR)path,CV_LOAD_IMAGE_ANYCOLOR); if(!img.empty()) { CString imageName; imageName = path; imageName.MakeReverse(); int index=imageName.Find('\\'); imageName = imageName.Left(index); imageName.MakeReverse(); //显示图像信息 HWND hWnd = ::FindWindow(NULL,"showPicture"); info.h.Format("%d",img.rows); info.w.Format("%d",img.cols); int depth; switch(img.depth()) { case 0 :; case 1 :depth=8;break; case 2 :; case 3 :depth=16;break; } info.depth.Format("%d",depth); index = imageName.Find('.'); info.format = imageName.Right(imageName.GetLength()-index-1); info.filename = imageName; HWND hEdit = ::GetDlgItem(hWnd,IDC_EDIT_H); // 取得控件的指针 ::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.h)); hEdit = ::GetDlgItem(hWnd,IDC_EDIT_W); // 取得控件的指针 ::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.w)); hEdit = ::GetDlgItem(hWnd,IDC_EDIT_DEPTH); // 取得控件的指针 ::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.depth)); hEdit = ::GetDlgItem(hWnd,IDC_EDIT_FORMAT); // 取得控件的指针 ::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.format)); hEdit = ::GetDlgItem(hWnd,IDC_EDIT_filename); // 取得控件的指针 ::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.filename)); //显示图像 namedWindow((LPCSTR)imageName, CV_WINDOW_NORMAL); resizeWindow((LPCSTR)imageName,img.cols,img.rows); imshow((LPCSTR)imageName,img); } else { MessageBox("fail to open!"); return; } } else { MessageBox("path is invalid!"); return; } } ::DragFinish (hDropInfo); //释放内存 i=0; delete []lpszFileName; }
FileButton.h中添加成员变量
public: struct info { CString depth; CString format; CString filename; CString h; CString w; }info;并添加
#include "image.h"
修改showPictureDlg.h
添加成员变量
public: CFileButton m_FileButton;添加头文件
#include "FileButton.h"
改写对话框的DoDataExchange函数
void CshowPictureDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_EDIT_H, Edit_h); DDX_Control(pDX, IDC_EDIT_W, Edit_w); DDX_Control(pDX, IDC_EDIT_FORMAT, Edit_format); DDX_Control(pDX, IDC_EDIT_DEPTH, Edit_depth); DDX_Control(pDX, IDC_EDIT_filename, Edit_filename); DDX_Control(pDX, IDC_BUTTON_OPEN, m_FileButton);//增加了这一句 }
附:涉及的知识点
1、CString的使用,例如字符串的提取、类型转换
参考:
http://blog.csdn.net/kelvin_yan/article/details/41082191
http://blog.csdn.net/kelvin_yan/article/details/41007951
http://blog.csdn.net/kelvin_yan/article/details/41042571
2、拖曳文件的功能
参考:
http://blog.csdn.net/kelvin_yan/article/details/41082299
3、SendMessage向控件发送消息。为什么要用这种方式?在对话框原本的cpp里是不需要这么麻烦的,但因为这里自定义了一个CFileButton类,不能通过Edit控件的成员变量来传值,只能用这种方法。
参考:
http://blog.csdn.net/kelvin_yan/article/details/41082525
http://blog.csdn.net/kelvin_yan/article/details/41082251
4、扩展控件功能的一种办法。这里通过新建一个CFileButton类,使Button控件支持文件拖曳的功能。很奇怪的一点:Button控件有一个接受文件的属性,但为什么就没有一个类似OnDropFiles的事件处理程序?或者是我不知道而已。
还有一种方法是自定义控件,但感觉挺麻烦的。这里要实现的功能比较简单,可能这种方式可用于实现一些复杂的功能。