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

来源:互联网 发布:淘宝福利关键词 编辑:程序博客网 时间:2024/05/21 08:47
最近老师让做一个处理图像的小软件,用了大概一个星期做出来了成品,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();//operationspublic:// 用于操作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;// 输出DIBpDoc->m_dib.DrawDib(pDC->m_hDC, &rcDest, pDoc->GetHObject(),&rcDIB, pDoc->GetDocPal());}
编译工程并运行,就可以打开文件并显示到程序的客户区了。





2 0