"Message Maps"、"Member Variables"中实现成员函数、成员变量等的设置。
4.5建立对话框资源
(3)向对话框资源中添加用户需要的控件、控件变量及其响应控件的消息函数。若添加消息响应函数,对源程序主要可做如下修改:首先向头文件(.h)中添加对应的成员函数声明,afx_msg说明此函数是被消息映射驱动的成员函数;其次,向实现文件(.cpp)中的消息映射宏里添加相应的消息与成员函数,完成控件消息与函数之间的映射;最后向实现文件(.cpp)中添加成员函数的定义。
(4)向程序中创建对话框派生类对象,添加代码(头文件.h、实现文件.cpp、视图类、文档类等)实现相应的对话框响应程序,调用相应函数显示对话框。
4.1.2对话框参数设置
利用对话框的模式进行参数设置,其中关键是结构元素大小和形状的设置,对于不同形状的操作对象要选择相对应的结构元素,可以通过对话框的形式来完成,这样既直观又容易实现,一目了然。该对话框内包含五部分内容【14】:第一部分是结构元素大小设置部分,可通过行数和列数的选择设定其大小,范围为1~7之间选择;第二部分是结构元素原点设置,原点是否在结构元素内虽不影响图像的处理效果,但会影响处理后的图像是否发生移动;第三部分是自定义结构元素部分,用户可以自己定义结构元素的形状;第四是操作次数输入框,通过设置操作次数,可以方便观察和比较如何才能得到最佳处理结果。但要注意的是:由于开运算和闭运算的幂等性质,此处的操作次数设置对其操作结果没有影响;第五部分是确定和取消键。
1、界面设置
(1)结构元素大小设置:建立两个下拉组合框IDC_RANK和IDC_COLUMN,分别输入结构元素的行数和列数。注意组合框只能建立Cstring类的变量,对以后的参数应用不太方便。还有一个大小确定按键IDC_SIZEOK用于确定设定的结构元素大小值。
(2)原点设置:两个Edit编辑框IDC_XORIG、IDC_YORIG,用以输入设定的原点坐标值。
(3)自定义结构元素:77的一组Radio按键IDC_Structure1~49,属性全部设定为Group。还有一个重新设置按钮IDC_RENEW,用于结构元素的重新设定。加上该控件,可以防止用户不小心将结构元素设置错误,大大方便了操作。
(4)操作次数:这是一个Edit编辑框,其对应ID为IDC_RUNTIMES。用来设置操作次数。
(5)确认和取消键。分别对应IDOK、IDCANCEL。
2、变量设置
这部分工作的要在MFC ClassWizard对话框下完成。即在"Member Variables" 栏中实现。包括"Control IDs"、"Type"、"Member"选项。
表4.1 对话框变量设置
对应界面部分 Control IDs Type Member(变量设置) 结构元素大小设置 IDC_RANK Cstring m_sRank IDC_COLUMN Cstring m_sColumn IDC_SIZEOK 原点设置 IDC_XORIG Int m_nXOrig IDC_YORIG Int m_nYOrig 自定义结构元素 IDC_Structure1~49 in或CButton m_cConrol1~49 操作次数 IDC_RUNTIMES Int m_nTimes 重新设置 IDC_RENEW Cbutton m_cRenew 确定、取消键 IDOK、IDCANCEL 4.1.3对话框的实现
上面的对话框实例分析中只是完成了对话框功能实现的准备工作,要想实现对话框的显示、具体设置功能的实现,还必须要考虑如何以菜单的模式实现对话框【15】。即点击下拉菜单相应的选项,如何实现对相应对话框的调用、显示与功能的实现(这部分实现要调用相应的算法实现文件,本程序中为PicCoding.cpp文件)。为了达到上述要求,还要对程序做如下改动:
(1) 将对话框类的头文件加入到在PicCodingView.cpp中,并在该实现文件中消息映射宏定义中完成控件值与对应函数响应的映射关系。接下来就是响应函数的添加,实现对按钮和对话框的响应,从而完成对话框的建立、显示、响应等。程序中的响应函数为OnCodeHuffman()、OnCodeShannon()、OnCodeRLE()和OnCodeLzw()。
(2) 在PicCoding.cpp中添加响应的算法实现代码,在PicCoding.h中添加相应的基本算法实现的函数原型声明。
(3) 另外,resource.h中会有定义的ID名称的各个ID值,这里不用担心,进行编译的时候会自动生成,不用自己特意去定义。
(4) 再者需要加入的就是相应的对话框类的具体头文件与实现文件。
4.2霍夫曼编码
在进行霍夫曼编码、香农-弗诺编码和行程编码之前,我们首先要对bmp图像格式进行定义,这样我们的编码平台才能识别".bmp"格式的图像并打开。在本次试验中,我们首先构造了自己的DIB函数库,即第三章所介绍的"与设备无关位图(DIB)函数库"。编程过程中,我们要把DIB函数库加入到工程中才行。"DIBAPI.cpp"即为构造的函数库。
4.2.1霍夫曼编码对话框
给工程添加一个名为"图像编码"的菜单,并添加一个名为"霍夫曼编码"的菜单,如图4.4所示。CdlgHuffman是一个新创建的对话框类,该对话框主要功能是计算指定序列的霍夫曼编码表,同时计算图像熵、平均码字长度和编码效率。
图4.7建立霍夫曼编码对话框
然后向PicCodingView.cpp中添加霍夫曼编码的调用函数"OnCodeHuffman()"。此函数是用来统计各灰度值出现的概率,并以对话框的形式显示通过算法计算出的结论值。
首先是通过CDib类中的GetBits()函数来获取图像像素的起始位置,因为本程序只支持256色的位图图像,所以要进行判断(如果不是256色的位图图像则弹出对话框提示"只支持256色位图图像")。然后通过CDib类中的GetWidth()和GetHeight()函数返回图像的宽度和高度,用于计算图像的像素总和及控制循环边界。用两个for的嵌套循环对图像的进行逐行扫描,以统计出每个灰度值出现的次数,再除以像素总和就可以得到每个灰度值的概率,此概率要参与到哈夫曼编码算法中。最后要显示出哈夫曼编码的结果。
资源文件DlgHuffman.cpp中主要介绍哈夫曼编码的算法,从视图类CDImageProcessView中的OnHuffmancoding函数中得到0-255各灰度值出现的概率,在下面的算法中要基于这个概率值进行哈夫曼编码。首先对这个概率值进行从小到大的冒泡排序,然后从概率大于0处开始编码,灰度值较小的编为1,灰度值较大的编为0,再将最小的两个灰度值相加,将加后的值与其他灰度值放在一起重新按从小到大排序,重复以上的步骤直到概率值相加为1。然后计算该图像的熵值、平均码字长度及编码效率。
以下是部分程序代码:
(1)计算灰度值:
for (i = 0; i < lHeight; i ++)
{for (j = 0; j < lWidth; j ++)
{lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;//指向图像指针
fFreq[*(lpSrc)] += 1; // 计数加1}}
lCountSum = lHeight * lWidth; // 计算图像象素总数
for (i = 0; i < iColorNum; i ++) // 计算各个灰度值出现的概率
{fFreq[i] /= (FLOAT)lCountSum; // 计算概率}
(2)创建对话框:
CDlgHuffman dlgPara; // 创建对话框
dlgPara.m_fFreq = fFreq; // 初始化变量值
dlgPara.m_iColorNum = iColorNum;
dlgPara.DoModal(); // 显示对话框
::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 解除锁定
EndWaitCursor(); // 恢复光标
}
4.2.2 霍夫曼编码运行结果演示
对256色位图图像"sdkd.bmp"进行霍夫曼编码压缩,如下图4.5所示。编码效率约为98.6%,图像熵值为2.76,平均码长2.80。
图4.8霍夫曼编码运行结果
霍夫曼编码具有以下优点
(1)有效的信源编码可取得较好的冗余压缩效果。
(
上一篇:
施工组织设计(小农水工程2011)
下一篇:
超市进销存管理系统的开发