在上一篇博客中我们已经绘制了MFC界面,在这篇博客中我们将加入响应代码,为MFC框架加入一个最主要的功能:打开一个目录。
一、加入相关头文件
这里头文件主要包括三类:opencv头文件、批量读取文件相关的头文件、CvvImage。这里须要强调CvvImage这个头文件,这个是用来关联OpenCv和picture控件,而且这个头文件是隶属于OpenCv1.x的,在2.x版本号中已经将这个类移除。因此须要手动下载这两个文件(CvvImage.h和CvvImage.cpp),下载地址:CvvImage。下载后将这两个文件放在project文件夹下:
然后在VS的解决方式资源管理器窗体中,右击该project,在快捷菜单中选择“加入->现有项”:
将这两个文件加入到当前project中:
加入完毕后,能够在代码中加入响应的头文件了,建议将include命令加入在GenderRecognitionMFCDlg.h头文件里:
#include <iostream> #include <sstream> #include <fstream> #include <opencv2opencv.hpp> #include "CvvImage.h" using namespace std; using namespace cv;
这里有两点须要强调:
(1)#include语句包括两种形式,“ #include<> ”和“ #include“” ”。这两种格式的差别在于优先搜索路径的不同。“ #include<> ”默认优先依照系统路径进行搜索,“ #include“” ”默认优先搜索当前的project文件夹。
(2)include语句的位置。大型project中的include语句要注意避免一个反复包括的问题,即要保证每条include语句仅仅运行一次,否则就会出现重定义类型的错误。C++提供两种机制来确保include语句运行的唯一性。一是通过“ifndef”宏来包围include代码块,二是通过“#pragma once”宏来实现,这里默认使用另外一种,因此全部的include语句应该位于“#pragma once”语句之后。
二、加入控件响应函数
因为读取显示图片的操作是通过“图像目录”button来控制的,因此须要为这个button加入响应的事件响应函数。方法很easy,在资源视图窗体中双击相应控件就可以,VS将自己主动加入响应函数:
三、打开目录。读取图片路径
接下来为OnBnClickedButtonImagefile()函数加入批量读取图片的代码。我们这里选用SHBrowseForFolder方法。关于这种方法我之前曾写过一篇博客来专门介绍,详细參见一种批量读取文件的方法——SHBrowseForFolder。注意一点,在SHBrowseForFolder方法中须要用到dir文件夹相关的操作函数(如opendir等),这算是Linux的移植版,因此须要借用dirent.h头文件,只是我们已经在之前下载的资源中提供了这个文件,仅仅需根据之前CvvImage文件的配置方法,加入到当前project中就可以:
接下来,向CGenderRecognitionMFCDlg类中加入若干成员变量,用以记录读取的文件夹以及文件的路径及属性,详细须要加入下面四个成员变量,各自是CString m_Path(图像文件路径)、char* m_ImageDir(文件结构)、DIR *m_pDir(文件夹结构)、struct dirent *m_pEnt(文件夹结构)。这里以m_pEnt为例。介绍VS中加入类成员变量的方法。
在类视图中,右击CGenderRecognitionMFCDlg类。在快捷菜单中选择“加入->加入变量”:
在弹出的向导窗体中。指定变量的属性。然后单击“完毕”button:
同理,加入其它三个成员变量(注意变量类型):
变量加入完毕后,就可以向OnBnClickedButtonImagefile()函数中加入对应代码:
/**********初始化变量**********/ CString str; //存储图像路径 BROWSEINFO bi; //用来存储用户选中的文件夹信息 TCHAR name[MAX_PATH]; //存储路径 ZeroMemory(&bi,sizeof(BROWSEINFO)); //清空文件夹相应的内存 bi.hwndOwner = GetSafeHwnd(); //得到窗体句柄 bi.pszDisplayName = name; /**********设置对话框并读取文件夹信息**********/ BIF_BROWSEINCLUDEFILES; bi.lpszTitle = _T("Select folder"); //对话框标题 bi.ulFlags = 0x80; //设置对话框形式 LPITEMIDLIST idl = SHBrowseForFolder(&bi); //返回所选中文件夹的ID SHGetPathFromIDList(idl,str.GetBuffer(MAX_PATH)); //将文件信息格式化存储到相应缓冲区中 str.ReleaseBuffer(); //与GerBuffer配合使用,清空内存 m_Path=str; //将路径存储在m_path中 if(str.GetAt(str.GetLength()-1)!='\') m_Path += "\"; UpdateData(FALSE); IMalloc * imalloc = 0; if (SUCCEEDED(SHGetMalloc(&imalloc))) { imalloc->Free (idl); imalloc->Release(); } /**********获取该路径下的第一个文件**********/ m_ImageDir = (LPSTR)(LPCTSTR)m_Path; m_pDir = opendir(m_ImageDir); for (int i = 0; i < 1; i ++) //过滤文件夹 .. 和 . { m_pEnt = readdir(m_pDir); }
有关SHBrowseForFolder的方法介绍,除了之前给出的那篇博客之外,这里再推荐两篇更为具体的博客:文件夹浏览(SHBrowseForFolder)以及使用SHBrowseForFolder函数打开文件文件夹对话框。
四、简单调试
完毕上面那段代码之后,进行一下简单调试。首先按下F7对project进行编译,在编译过程中注意将调试器版本号设置为X64(64位)。编译通过后,设置断点,按下F5进行调试执行。此时单击“图像目录”button,将弹出打开目录对话框:
选择一个目录,然后查看各个变量的情况:
可见。m_Path保存了当前选择的目录路径。
在下一篇博文中我们将通过这个变量来完毕相应目录目录下图像文件的遍历和显示。