2021.3.6——2021.3.7
本实验创建MFC应用程序,实现通过窗口选择图像文件,并将图像显示出来的功能。
在VisualStudio 2017中新建项目,创建“MFC应用程序”,项目名为“ImageProcessing”,选择项目路径。
按下述步骤完成项目创建:
选择CScrollView,如果图像大小超过窗口,可以拖动滚动条。
点击“完成”,完成项目创建。现在VisualStudio已经为我们创建好了程序的框架。
点击运行,可以看到虽然自己一行代码都没写,但应用程序已经可以运行了,只是里面的选项都没有对应的功能。
查看源文件列表。
因为目前只实现打开并显示图片的功能,只涉及对文件的操作和显示的视图操作,故只修改ImageProcessingView.cpp和ImageProcessingDoc.cpp文件。
查看代码可以看到,在这里Visual Studio已经为我们生成好了主要的程序框架,源文件都包括了对应的头文件
查看并修改ImageProcessingDoc.cpp对应的头文件ImageProcessingDoc.h。
对CImageProcessingDoc类添加新的成员变量,用于存放“原始图像”和“处理后的图像”,图片文件有多种格式(如PEG、GIF、BMP和PNG格式),对每一种格式都自己手动实现解码非常麻烦,而CImage类已经提供了相应的接口函数,可以装入、显示、转换和保存多种格式的图像文件,我们只需调用就可以直接打开图片,打开后图像将以统一的格式放在CImage类的对象中
class CImageProcessingDoc : public CDocument
{
protected: // 仅从序列化创建
CImageProcessingDoc() noexcept;
DECLARE_DYNCREATE(CImageProcessingDoc)
// 特性
public:
CImage m_sImage; //原始图像
CImage m_rImage; //处理后的图像
//省略其余
打开“资源视图”,可以看到这里面有组成程序窗口的各种组件,包括Dialog(对话框),Icon(图标),Menu(菜单)等等。
选择Menu中的IDR_MAINFEAME,可以看到这里可以对主菜单中的各种选项进行编辑。
在此程序中不需要新建文件的功能,故右键“新建”项将其删除。同样方法删除“编辑”项。
点击“打开”选项,在右下角的“属性”框中对选项中的文字内容(即“Caption”栏)进行编辑,将“打开”改为“打开图像文件”。
本程序只实现打开图片并显示的功能,右键刚刚修改的“打开图像文件”选项,点击“添加事件处理程序”。
按照本文之前的说明,与打开文件相关的是文档类,在“类列表”中选择“CImageProcessingDoc”,点击“添加编辑”。
可以看到在ImageProcessingDoc.cpp文件(功能实现代码)中新增的OnFileOpen()函数,编写这个函数。
该函数主要实现了 通过窗口选择图像文件,并加载到CImage类对象中 的功能。函数代码如下:
void CImageProcessingDoc::OnFileOpen()
{
// TODO: 在此添加命令处理程序代码
CString strFilter;
CSimpleArray<GUID> aguidFileTypes;
HRESULT hResult;
// 获取CImage支持的图像文件的过滤字符串
hResult = m_sImage.GetExporterFilterString(strFilter, aguidFileTypes, _T("All Image Files"));
if (FAILED(hResult))
{
AfxMessageBox(_T("GetExporterFilter函数失败!"));
return;
}
CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, strFilter);
if (IDOK != dlg.DoModal())
return;
// 销毁原有文件内容
m_sImage.Destroy();
m_rImage.Destroy();
// 将外部图像文件装载到CImage对象中
hResult = m_sImage.Load(dlg.GetPathName());
if (FAILED(hResult))
{
AfxMessageBox(_T("图像文件加载失败!"));
return;
}
// 要求图像为24位真彩图,32位相对于24位还多8位存放透明度
if (m_sImage.GetBPP() != 24)
{
m_sImage.Destroy();
AfxMessageBox(_T("只处理24位色图像!"));
return;
}
// 设置主窗口标题栏内容
CString str;
str.LoadString(AFX_IDS_APP_TITLE);
AfxGetMainWnd()->SetWindowText(str + " - " + dlg.GetFileName());
InvalidateRect(NULL, NULL, FALSE); // 刷新窗口
}
同样在ImageProcessingView.cpp文件中,编写OnDraw()函数。代码如下:
void CImageProcessingView::OnDraw(CDC* pDC)
{
CImageProcessingDoc* pDoc = GetDocument(); //获取文档类Doc对象的指针
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// 原始图像显示在窗口左上角
if (!pDoc->m_sImage.IsNull())
pDoc->m_sImage.Draw(pDC->m_hDC, 0, 0);
// 目标图像从原始图像右边10个像素的位置开始显示
if (!pDoc->m_rImage.IsNull())
pDoc->m_rImage.Draw(pDC->m_hDC, pDoc->m_sImage.GetWidth() + 10, 0);
}
至此代码编写完成,点击运行程序,测试功能。可以看到“文件”菜单下的“打开图像文件”选项。
点击“打开图像文件”,选择lena的24位bmp图片。
可以看到图像显示在应用窗口中,说明实现了选择图片文件并显示的功能,完成了实验目标。
本次实验是对于MFC项目的初步应用实践,对VisualStudio C++中图像相关类(如CImage)有了初步的了解,并掌握了相关的数字图像基础知识,如采样、量化等等。