mfc制作图像处理软件总结(一)

最近老师让做一个处理图像的小软件,用了大概一个星期做出来了成品,MFC上我算是新手,一路摸索过来也算是收获不少吧,现在软件也做完了,给自己总结一下在学习过程中的收获和不足。

首先放出一下软件的运行截图,主要是做了灰度图像的几何变换、正交变换、图像增强、二值化处理、形态学处理、图像分割等功能。代码主要参考了《visual c++数字图象处理技术详解》以及网上的一些技术文章,完整的工程已上传至csdn:http://download.csdn.net/detail/zzucode/7672489

《mfc制作图像处理软件总结(一)》

灰度图像处理主要操作的是设备无关位图(DIB),由于mfc本身没有提供DIB的一个完整的类,只是提供了一些API接口和结构体,因此需要自己创建一个DIB类,主要实现位图的载入,保存,绘制及返回位图信息等操作。

首先使用mfc向导创建一个单文档应用程序,不使用unicode编码,然后在源文件中添加DIB类的头文件Dib.h和Dib.cpp,具体的头文件如下:

class CDib 
{
public:
	CDib();
	virtual ~CDib();
	//operations
	public:
	// 用于操作DIB的函数声明
	BOOL   DrawDib(HDC, LPRECT,HGLOBAL, LPRECT,CPalette*);//显示位图
	BOOL   ConstructPalette(HGLOBAL,CPalette* );          //构造逻辑调色板
	LPSTR  GetBits(LPSTR);                                //取得位图数据的入口地址
	DWORD  GetWidth(LPSTR);                               //取得位图的宽度
	DWORD  GetHeight(LPSTR);                              //取得位图的高度
	WORD   GetPalSize(LPSTR);                             //取得调色板的大小
	WORD   GetColorNum(LPSTR);                            //取得位图包含的颜色数目
	WORD   GetBitCount(LPSTR);                            //取得位图的颜色深度
	HGLOBAL CopyObject(HGLOBAL);                          //用于复制位图对象

	BOOL      SaveFile(HGLOBAL , CFile&);                    //存储位图为文件
	HGLOBAL   LoadFile(CFile&);                           //从文件中加载位图
	BOOL      IsEmpty();
	// 在对图像进行处理时,针对位图的字节宽度必须是4的倍数的这一要求,
	//我们设计了函数GetRequireWidth,来处理这种比较特殊的情况
	int     GetReqByteWidth(int );                     //转换后的字节数
	long    GetRectWidth(LPCRECT );                    //取得区域的宽度
	long    GetRectHeight(LPCRECT);                    //取得区域的高度
public:
	void ClearMemory();
	void InitMembers();
public:
	LPBITMAPINFO        	lpbminfo;// 指向BITMAPINFO结构的指针
	LPBITMAPINFOHEADER  	lpbmihrd;	//指向BITMAPINFOHEADER结构的指针
	BITMAPFILEHEADER<span style="white-space:pre">	</span>bmfHeader;  //BITMAPFILEHEADER结构
	LPSTR<span style="white-space:pre">			</span>lpdib;      //指向DIB的指针
	LPSTR<span style="white-space:pre">			</span>lpDIBBits;  // DIB像素指针
	DWORD<span style="white-space:pre">			</span>dwDIBSize;  //DIB大小
	HGLOBAL<span style="white-space:pre">			</span>m_hDi       //DIB对象的句柄
	RGBQUAD*<span style="white-space:pre">		</span>lpRgbQuag;  //指向颜色表的指针
};

DIB类的实现文件太长,就不再贴出来了,《visual c++数字图象处理技术详解》上有完整的源码,有感兴趣的朋友可以自己去看。

将Dib的实现文件添加进来之后,接下来就需要载入图像并在文档客户区显示,首先在工程C**Doc类的头文件中声明一个Dib类的对象并定义一些操作:

// 特性
public:
	CDib m_dib;	//声明一个DIB对象
	CString m_szPathName;//图片文件路径
// 操作
public:
	HGLOBAL GetHObject() const	//获取Dib对象的句柄
	{ return m_hDIB;}
	CPalette *GetDocPal() const	//获取调色板指针
	{ return m_palDIB;}
	CSize GetDocDimension() const	//
	{ return m_sizeDoc;}
	void UpdateObject(HGLOBAL hDIB);	//更新DIB对象
// 实现
public:
	void SetDib();		//获取Dib对象
public:
	HGLOBAL m_hDIB;
	CPalette *m_palDIB;
	CSize m_sizeDoc;

然后在C**Doc类的实现文件的构造函数中添加

// TODO: 在此添加一次性构造代码
	m_hDIB = NULL;
	m_palDIB = NULL;
	m_sizeDoc = CSize(1,1);

在析构函数中添加

if (m_hDIB != NULL)	//判断是否有dib对象
	{
		::GlobalFree(m_hDIB);
	}

	if (m_palDIB != NULL)	//判断是否有调色板
	{
		delete m_palDIB;
	}

然后重载C**Doc类的OnOpenDocument函数

// TODO:  在此添加您专用的创建代码
	CFile file;
	if (!file.Open(lpszPathName,CFile::modeRead | CFile::shareDenyWrite))
	{
		//只读方式打开文件
		return FALSE;
	}
	DeleteContents();//删除文档中数据,确保载入图像数据之前文档为空
	m_hDIB = m_dib.LoadFile(file);

	m_szPathName = lpszPathName;
	if (m_hDIB == NULL)
	{
		return FALSE;
	}
	SetDib();
	if (m_hDIB == NULL)
	{
		AfxMessageBox("读取图像时出错!");
		return FALSE;
	}
	SetPathName(lpszPathName);//设置文件名称

	return TRUE;

其中setdib函数主要是在载入位图数据后创建调色板,具体代码如下

void CImgProcessDoc::SetDib()
{
	LPSTR lpdib = (LPSTR) ::GlobalLock(m_hDIB);//保持图片数据内存一直有效
	if (m_dib.GetWidth(lpdib) > INT_MAX ||m_dib.GetHeight(lpdib) > INT_MAX)// 判断图像是否过大
	{
		::GlobalUnlock((HGLOBAL) m_hDIB);				
		::GlobalFree((HGLOBAL) m_hDIB);	// 释放DIB对象			
		m_hDIB = NULL;// 设置DIB为空		
		AfxMessageBox("初始化失败!"); 		
		return;
	}

	m_sizeDoc = CSize((int)m_dib.GetWidth(lpdib), (int)m_dib.GetHeight(lpdib));// 设置文档大小	
	::GlobalUnlock((HGLOBAL) m_hDIB);	
	m_palDIB = new CPalette;// 创建新调色板		
	if (m_palDIB == NULL)// 判断是否创建成功
	{		
		::GlobalFree((HGLOBAL) m_hDIB);	// 失败		
		m_hDIB = NULL;// 设置DIB对象为空
		return;
	}	
	// 调用CreateDIBPalette来创建调色板
	if (m_dib.ConstructPalette(m_hDIB, m_palDIB) == NULL)
	{				
		delete m_palDIB;// 删除				
		m_palDIB = NULL;// 设置为空	
		return;// 返回空
	}
}

这时候编译工程并运行,点击打开一个位图文件就可以将位图文件的信息和数据载入内存,但是打开之后并没有在客户区显示,这时候需要重载C**View类的OnDraw函数

// TODO: 在此处为本机数据添加绘制代码
	HGLOBAL hDIB = pDoc->GetHObject();

	// 判断DIB是否为空
	if (hDIB != NULL)
	{
		LPSTR lpDibSection = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);

		// 获取DIB宽度
		int cxDIB = (int) pDoc->m_dib.GetWidth(lpDibSection);

		// 获取DIB高度
		int cyDIB = (int) pDoc->m_dib.GetHeight(lpDibSection);

		::GlobalUnlock((HGLOBAL) hDIB);

		CRect rcDIB;
		rcDIB.top = rcDIB.left = 0;
		rcDIB.right = cxDIB;
		rcDIB.bottom = cyDIB;

		CRect rcDest= rcDIB;	
		// 输出DIB
		pDoc->m_dib.DrawDib(pDC->m_hDC, &rcDest, pDoc->GetHObject(),
			&rcDIB, pDoc->GetDocPal());
	}

编译工程并运行,就可以打开文件并显示到程序的客户区了。

    原文作者:亚瑟的大陆
    原文地址: https://blog.csdn.net/zzucode/article/details/38084243
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞