您的位置:首页 > 编程语言 > C语言/C++

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

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

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



灰度图像处理主要操作的是设备无关位图(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());
}
编译工程并运行,就可以打开文件并显示到程序的客户区了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息