环境: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;
至此,运行程序可以实现功能1。
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"
修改showPictureDlg.cpp
改写对话框的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);//增加了这一句
}
至此,运行程序可以实现功能2和功能1。
附:涉及的知识点
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的事件处理程序?或者是我不知道而已。
还有一种方法是自定义控件,但感觉挺麻烦的。这里要实现的功能比较简单,可能这种方式可用于实现一些复杂的功能。