值相加为1。然后计算该图像的熵值、平均码字长度及编码效率。具体算法如下代码所示:
BOOL CHuffmanCoding::OnInitDialog() { //调用默认的对话框初始化函数 CDialog::OnInitDialog(); int i; // 循环变量 int j;
// 循环变量 int k;
// 循环变量
// 图像灰度出现概率中间结果的数组 double * temp;
// 数组用来存放灰度值和其位置之间的对应关系
int * turn;
// 分配内存 m_strCode = new CString[graygrade]; // 分配内存 turn = new int[graygrade]; // 分配内存
temp = new double[graygrade];
for (i = 0; i < graygrade; i ++) {
//将grayfreq的值传给temp temp[i] = grayfreq[i]; //记录灰度位置 turn[i] = i;
}
// 中间变量
double te;
//用冒泡法对进行灰度值出现的概率排序从小到大 //同时改变灰度值位置的映射关系 for (j = 0; j < graygrade - 1; j ++) { for (i = 0; i < graygrade - j - 1; i ++) { //如果前面的值大于后面的值
if (temp[i] > temp[i + 1])
{
//二者的值互换
te = temp[i]; temp[i] = temp[i + 1];
temp[i + 1] = te;
// 将i和i+1灰度的位置值互换
for (k = 0; k < graygrade; k ++)
{ if (turn[k] == i)
第 11 页 共 32 页
turn[k] = i + 1;
else if (turn[k] == i + 1) turn[k] = i;
}
}
}
}
// 从灰度概率大于0处开始编码
for (i = 0; i < graygrade - 1; i ++) { if (temp[i] > 0)
break;
}
for (; i < graygrade - 1; i ++) { // 更新m_strCode
for (k = 0; k < graygrade; k ++) {
// 灰度值是否i
if (turn[k] == i)
{ // 灰度值较小的码字加1
m_strCode[k] = \ }
else if (turn[k] == i + 1)
{ //灰度值较大的码字加0 m_strCode[k] = \
}
}
// 概率最小的两个概率相加,保存在temp[i + 1]中
temp[i + 1] = temp[i]+temp[i + 1];
// 改变映射关系 for (k = 0; k < graygrade; k ++) { // 将位置为i的灰度值i改为灰度值i+1
if (turn[k] == i)
{
turn[k] = i + 1;
} }
// 重新排序 从i+1开始 for (j = i + 1; j < graygrade - 1; j ++) { if (temp[j] > temp[j + 1]) { te = temp[j]; // 互换
temp[j] = temp[j + 1];
第 12 页 共 32 页
temp[j + 1] = te;
// 将i和i+1灰度的位置值互换 for (k = 0; k < graygrade; k ++) { if (turn[k] == j) turn[k] = j + 1; else if (turn[k] == j + 1) turn[k] = j;
}
} else
break; // 退出循环 }
}
// 计算图像熵
for (i = 0; i < graygrade; i ++) { if (grayfreq[i] > 0)
{ // 计算图像熵
m_shang -= grayfreq[i] * log(grayfreq[i]) / log(2.0); }
}
// 计算平均码字长度 for (i = 0; i < graygrade; i ++) { m_length += grayfreq[i] * m_strCode[i].GetLength(); //累加}
// 计算编码效率
m_effection = m_shang / m_length;
// 保存变动 UpdateData(FALSE); // 字符串变量,列表项目的显示 CString listname; // 控件CodingList的ITEM LV_ITEM codingItem; // 保存控件ListCtrl中添加的ITEM编号 int nItem2View; // 设置CListCtrl控件样式
m_codinglist.ModifyStyle(LVS_TYPEMASK, LVS_REPORT); // 给List控件添加Header
m_codinglist.InsertColumn(0, \像素灰度\m_codinglist.InsertColumn(1, \灰度概率\m_codinglist.InsertColumn(2, \编码码字\m_codinglist.InsertColumn(3, \码字长度\
第 13 页 共 32 页
// 设置样式为文本
codingItem.mask = LVIF_TEXT; // 添加显示 for (i = 0; i < graygrade; i ++) }
{ // 第一列显示 }
codingItem.iItem = m_codinglist.GetItemCount(); listname.Format(\codingItem.iSubItem = 0; //显示像素灰度
codingItem.pszText= (LPTSTR)(LPCTSTR)listname; nItem2View = m_codinglist.InsertItem(&codingItem); codingItem.iItem = nItem2View; // 第二列显示
codingItem.iSubItem = 1; listname.Format(\
codingItem.pszText = (LPTSTR)(LPCTSTR)listname; m_codinglist.SetItem(&codingItem); // 第三列显示
codingItem.iSubItem = 2;
codingItem.pszText = (LPTSTR)(LPCTSTR)m_strCode[i]; m_codinglist.SetItem(&codingItem); // 第四列显示
codingItem.iSubItem = 3;
listname.Format(\codingItem.pszText = (LPTSTR)(LPCTSTR)listname; m_codinglist.SetItem(&codingItem);
delete turn; // 内存释放 delete temp;
return TRUE; // 返回TRUE
5.1.2 视图类On Huffman coding()函数
此函数是用来统计各灰度值出现的概率,并以对话框的形式显示通过算法计算出的结论值。
首先是通过CDib类中的GetBits()函数来获取图像像素的起始位置,因为本程序只支持256色的位图图像,所以要进行判断(如果不是256色的位图图像则弹出对话框提示“只支持256色位图图像”)。然后通过CDib类中的GetWidth()和GetHeight()函数返回图像的宽度和高度,用于计算图像的像素总和及控制循环边界。用两个for的嵌套循环对图像的进行逐行扫描,以统计出每个灰度值出现的次
第 14 页 共 32 页
数,再除以像素总和就可以得到每个灰度值的概率,此概率要参与到哈夫曼编码算法中。最后要显示出哈夫曼编码的结果,本程序是通过对话框来显示的。
void CDImageProcessView::OnHuffmancoding() { // 获取文档 CDImageProcessDoc* pDoc = GetDocument(); //指向源图像的指针 unsigned char* lpSrc;
// 指向DIB的指针 LPSTR lpDIB; // 指向DIB象素指针
LPSTR lpDIBBits;
//图像灰度等级数 int graygrade;
//锁定DIB lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHObject()); //找到DIB图像象素起始位置 lpDIBBits = pDoc->m_dib.GetBits(lpDIB); // 判断是否是8-bpp位图
if (pDoc->m_dib.GetColorNum(lpDIB) != 256)
{ // 提示用户 MessageBox(\目前只支持256色位图!\系统提示\
MB_ICONINFORMATION | MB_OK);
// 解除锁定
::GlobalUnlock((HGLOBAL) pDoc->GetHObject()); return; // 返回
}
//灰度等级数为256
graygrade=pDoc->m_dib.GetColorNum(lpDIB); //各灰度等级出现的概率
double * grayfreq; //图像宽度
int width;
//图像高度 int height; width=pDoc->m_dib.GetWidth(lpDIB); height=pDoc->m_dib.GetHeight(lpDIB); //更改光标形状
BeginWaitCursor(); //分配内存
grayfreq = new double[graygrade]; //像素数目
int graySum;
int i;
第 15 页 共 32 页