多媒体 图像的哈夫曼编码实现.docx
《多媒体 图像的哈夫曼编码实现.docx》由会员分享,可在线阅读,更多相关《多媒体 图像的哈夫曼编码实现.docx(22页珍藏版)》请在冰豆网上搜索。
![多媒体 图像的哈夫曼编码实现.docx](https://file1.bdocx.com/fileroot1/2023-2/5/35f0ca06-5bed-4186-9ede-9e85cc7aeaf9/35f0ca06-5bed-4186-9ede-9e85cc7aeaf91.gif)
多媒体图像的哈夫曼编码实现
实验二图像的哈夫曼编码实现
一实验目的
使学生掌握图像的哈夫曼编码及哈夫曼编码的实现过程。
二实验环境
具有多媒体处理功能的计算安装有Windows操作系统,安装有Visualc++6.0程序设计软件。
三实验要求
学习相关理论指导,掌握相关程序设计知识;按照实验步骤要求完成程序设计任务,书写实验报告,试验报告中要求包含程序实现的主要程序代码和程序运行结果或结果说明。
四实验内容和实验步骤
1、使用应用程序向导生成哈夫曼编码程序框架和用于数据显示的界面
图2.1显示界面
1)创建多文档应用程序:
HuffmanExp
(1)使用资源管理制作对话框IDD_DLG_HUFFMAN
图2.2资源管理制作对话框
资源号分别为:
IDC_LST_Table,IDC_EDIT1,IDC_EDIT2,IDC_EDIT3
图2.3资源管理制作对话框2
(2)对应的数据成员定义为:
CListCtrlm_lstTable;
doublem_dEntropy;
doublem_dAvgCodeLen;
doublem_dEfficiency;
(3)为该对话框定义类CDlgHuffman
classCDlgHuffman:
publicCDialog
{
//Construction
public:
CDlgHuffman(CWnd*pParent=NULL);//standardconstructor
//DialogData
//{{AFX_DATA(CDlgHuffman)
enum{IDD=IDD_DLG_HUFFMAN};
CListCtrlm_lstTable;
doublem_dEntropy;
doublem_dAvgCodeLen;
doublem_dEfficiency;
//}}AFX_DATA
public:
//灰度级别数目
intm_iColorNum;
//各个灰度值出现频率
FLOAT*m_fFreq;
//哈夫曼编码表
CString*m_strCode;
//Overrides
//ClassWizardgeneratedvirtualfunctionoverrides
//{{AFX_VIRTUAL(CDlgHuffman)
protected:
virtualvoidDoDataExchange(CDataExchange*pDX);//DDX/DDVsupport
//}}AFX_VIRTUAL
//Implementation
protected:
//Generatedmessagemapfunctions
//{{AFX_MSG(CDlgHuffman)
virtualBOOLOnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
3)重载视图类的OnInitialUpdate()函数,用于获取DIB文件的信息来设置滚动显示范围。
voidCHuffmanExpView:
:
OnInitialUpdate()
{
CScrollView:
:
OnInitialUpdate();
CHuffmanExpDoc*pDoc=GetDocument();
CSizesizeTotal(pDoc->m_pDib->GetWidth(),pDoc->m_pDib->GetHeight());
SetScrollSizes(MM_TEXT,sizeTotal);
CMainFrame*pAppFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;
ASSERT_KINDOF(CMainFrame,pAppFrame);
CRectrc;
pAppFrame->GetClientRect(&rc);
if(rc.Width()>=sizeTotal.cx&&rc.Height()>=sizeTotal.cy&&
(sizeTotal.cx>0||sizeTotal.cy>0))
ResizeParentToFit(FALSE);
}
4)重载视图类的OnDraw(CDC*pDC)函数实现图像显示。
voidCHuffmanExpView:
:
OnDraw(CDC*pDC)
{
CHuffmanExpDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
//TODO:
adddrawcodefornativedatahere
if(!
pDoc->m_pDib->IsEmpty())
pDoc->m_pDib->Display(pDC,0,0);
}
其中CDib类的各成员函数为:
classCDib:
publicCObject
{
DECLARE_SERIAL(CDib)
//Publicmemberfunction
public:
//constructor
CDib();
//create
BOOLCreate(DWORDdwWidth,DWORDdwHeight);
BOOLCreate(DWORDdwWidth,DWORDdwHeight,WORDwBitCount);
BOOLCreate(LPBYTElpDIB);
BOOLCreate(LPBYTElpDIB,//DIBpointer
WORDwBitCount);//bits/pixel
BOOLCreate(HBITMAPhBitmap);//DIBSection
BOOLCreate(HBITMAPhBitmap,//DIBSection
WORDwBitCount);//bits/pixel
BOOLCreate(HBITMAPhBitmap,//Bitmaphandle
HPALETTEhPalette);//Palettehandle
BOOLCreate(HBITMAPhBitmap,//Bitmaphandle
HPALETTEhPalette,//Palettehandle
WORDwBitCount);//bits/pixel
BOOLCreate(CRectrcScreen);
BOOLCreate(HWNDhWnd,WORDfPrintArea);
BOOLCreate(HWNDhWnd,CRectrcClientArea);
//load/save
BOOLLoad(UINTuIDS,LPCTSTRlpszDibType);
BOOLLoad(LPCTSTRlpszDibRes,LPCTSTRlpszDibType);
BOOLLoad(LPCTSTRlpszDibFile);
BOOLSave(LPCTSTRlpszDibFile);
BOOLRead(CFile*pFile);
BOOLWrite(CFile*pFile);
//clone
CDib*Clone();
//deconstructor
virtual~CDib();
//destroy
voidDestroy();
//overlayingSerialize
virtualvoidSerialize(CArchive&ar);
//display
BOOLDisplay(CDC*pDC,intxDest,intyDest,intnWidthDest,intnHeightDest,intxSrc,intySrc,DWORDdwRop=SRCCOPY);
BOOLDisplay(CDC*pDC,intxDest,intyDest,intnWidthDest,intnHeightDest,intxSrc,intySrc,intnWidthSrc,intnHeightSrc,DWORDdwRop=SRCCOPY);
BOOLDisplay(CDC*pDC,intx,inty,DWORDdwRop=SRCCOPY);
BOOLDisplay(CDC*pDC,CRectrcDest,CRectrcSrc,DWORDdwRop=SRCCOPY);
BOOLDisplayPalette(CDC*pDC,CRectrc);
//DCformodifyDIB
CDC*BeginPaint(CDC*pDC);
voidEndPaint();
//DDBandpalette
BOOLBuildBitmap();
BOOLBuildPalette();
//attributes
BOOLIsEmpty();
DWORDGetCompression();
WORDGetBitCount();
LONGGetWidth();
LONGGetHeight();
LONGGetWidthBytes();
WORDGetColorNumber();
WORDGetPaletteSize();
CBitmap*GetBitmap();
CPalette*GetPalette();
HANDLEGetHandle();
LPBYTEGetBitsPtr();
COLORREFGetPixel(LONGx,LONGy);
LONGGetPixelOffset(LONGx,LONGy);
//privatememberfunction
private:
BOOLUpdateInternal();
//publicmemberdata
public:
HDIBm_hDib;
HBITMAPm_hBitmap;//handleofDIBSection
CPalette*m_pPalette;
CBitmap*m_pBitmap;
//privatememberdata
private:
//fordrawinginDIB
CDC*m_pMemDC;
CBitmap*m_pBitmapTmp;
CPalette*m_pPaletteTmp;
};
其函数定义参考例程中的Dib.cpp文件。
2、添加[图像编码]菜单及子菜单[哈夫曼编码],使用该菜单打开用于显示哈夫曼编码信息的对话框,执行相应哈夫曼编码处理和显示。
(1)创建菜单资源。
[哈夫曼编码]菜单资源号为:
ID_HUFFMAN
(2)定义菜单命令响应函数
voidCHuffmanExpView:
:
OnHuffman()
{
//TODO:
Addyourcommandhandlercodehere
//查看哈夫曼编码表
//获取文档
CHuffmanExpDoc*pDoc=GetDocument();
//指向源图像象素的指针
unsignedchar*lpSrc;
//指向DIB的指针
LPBYTElpDIB;
//指向DIB象素指针
LPBYTElpDIBBits;
//DIB的高度
LONGlHeight;
//DIB的宽度
LONGlWidth;
//图像每行的字节数
LONGlLineBytes;
//图像象素总数
LONGlCountSum;
//循环变量
LONGi;
LONGj;
//保存各个灰度值频率的数组指针
FLOAT*fFreq;
//获取当前DIB颜色数目
intiColorNum;
//锁定DIB
lpDIB=(LPBYTE):
:
GlobalLock((HGLOBAL)pDoc->m_pDib->m_hDib);
//找到DIB图像象素起始位置
lpDIBBits=:
:
FindDIBBits(lpDIB);
//获取当前DIB颜色数目
iColorNum=:
:
DIBNumColors(lpDIB);
//判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图,其它的可以类推)
if(iColorNum!
=256)
{
//提示用户
MessageBox("目前只支持256色位图哈夫曼编码!
","系统提示",
MB_ICONINFORMATION|MB_OK);
//解除锁定
:
:
GlobalUnlock((HGLOBAL)pDoc->m_pDib->m_hDib);
//返回
return;
}
//更改光标形状
BeginWaitCursor();
//分配内存
fFreq=newFLOAT[iColorNum];
//计算DIB宽度
lWidth=:
:
DIBWidth(lpDIB);
//计算DIB高度
lHeight=:
:
DIBHeight(lpDIB);
//计算图像每行的字节数
lLineBytes=WIDTHBYTES(lWidth*8);
//重置计数为0
for(i=0;i{
//清零
fFreq[i]=0.0;
}
//计算各个灰度值的计数(对于非256色位图,此处给数组fFreq赋值方法将不同)
for(i=0;i{
for(j=0;j{
//指向图像指针
lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*i+j;
//计数加1
fFreq[*(lpSrc)]+=1;
}
}
//计算图像象素总数
lCountSum=lHeight*lWidth;
//计算各个灰度值出现的概率
for(i=0;i{
//计算概率
fFreq[i]/=(FLOAT)lCountSum;
}
//计算各个灰度级出现的频率结束
/*****************************************************************************/
//创建对话框
CDlgHuffmandlgPara;
//初始化变量值
dlgPara.m_fFreq=fFreq;
dlgPara.m_iColorNum=iColorNum;
//显示对话框
dlgPara.DoModal();
//解除锁定
:
:
GlobalUnlock((HGLOBAL)pDoc->m_pDib->m_hDib);
//恢复光标
EndWaitCursor();
}
(3)
BOOLCDlgHuffman:
:
OnInitDialog()
{
//CDialog:
:
OnInitDialog();
//TODO:
Addextrainitializationhere
//字符串变量
CStringstr;
//循环变量
LONGi;
LONGj;
LONGk;
//中间变量
FLOATfT;
//ListCtrl的ITEM
LV_ITEMlvitem;
//中间变量,保存ListCtrl中添加的ITEM编号
intiActualItem;
//调用默认得OnInitDialog()函数
CDialog:
:
OnInitDialog();
//初始化变量
m_dEntropy=0.0;
m_dAvgCodeLen=0.0;
//计算图像熵
for(i=0;i{
//判断概率是否大于0
if(m_fFreq[i]>0)
{
//计算图像熵
m_dEntropy-=m_fFreq[i]*log(m_fFreq[i])/log(2.0);
}
}
//保存计算中间结果的数组
FLOAT*fTemp;
//保存映射关系的数组
int*iMap;
//分配内存
fTemp=newFLOAT[m_iColorNum];
iMap=newint[m_iColorNum];
m_strCode=newCString[m_iColorNum];
//初始化fTemp为m_fFreq
for(i=0;i{
//赋值
fTemp[i]=m_fFreq[i];
iMap[i]=i;
}
//用冒泡法对进行灰度值出现的概率排序,结果保存在数组fTemp中
for(j=0;j{
for(i=0;i{
if(fTemp[i]>fTemp[i+1])
{
//互换
fT=fTemp[i];
fTemp[i]=fTemp[i+1];
fTemp[i+1]=fT;
//更新映射关系
for(k=0;k{
//判断是否是fTemp[i]的子节点
if(iMap[k]==i)
{
//改变映射到节点i+1
iMap[k]=i+1;
}
elseif(iMap[k]==i+1)
{
//改变映射到节点i
iMap[k]=i;
}
}
}
}
}
//////////////////////////////////////////////////////////
//计算哈夫曼编码表
//找到概率大于0处才开始编码
for(i=0;i{
//判断概率是否大于0
if(fTemp[i]>0)
{
break;
}
}
//开始编码
for(;i{
//更新m_strCode
for(k=0;k{
//判断是否是fTemp[i]的子节点
if(iMap[k]==i)
{
//改变编码字符串
m_strCode[k]="1"+m_strCode[k];
}
elseif(iMap[k]==i+1)
{
//改变编码字符串
m_strCode[k]="0"+m_strCode[k];
}
}
//概率最小的两个概率相加,保存在fTemp[i+1]中
fTemp[i+1]+=fTemp[i];
//改变映射关系
for(k=0;k{
//判断是否是fTemp[i]的子节点
if(iMap[k]==i)
{
//改变映射到节点i+1
iMap[k]=i+1;
}
}
//重新排序
for(j=i+1;j{
if(fTemp[j]>fTemp[j+1])
{
//互换
fT=fTemp[j];
fTemp[j]=fTemp[j+1];
fTemp[j+1]=fT;
//更新映射关系
for(k=0;k{
//判断是否是fTemp[i]的子节点
if(iMap[k]==j)
{
//改变映射到节点j+1
iMap[k]=j+1;
}
elseif(iMap[k]==j+1)
{
//改变映射到节点j
iMap[k]=j;
}
}
}
else
{
//退出循环
break;
}
}
}
//计算平均码字长度
for(i=0;i{
//累加
m_dAvgCodeLen+=m_fFreq[i]*m_strCode[i].GetLength();
}
//计算编码效率
m_dEfficiency=m_dEntropy/m_dAvgCodeLen;
//保存变动
UpdateData(FALSE);
//////////////////////////////////////////////////////////
//输出计算结果
//设置List控件样式
m_lstTable.ModifyStyle(LVS_TYPEMASK,LVS_REPORT);
//给List控件添加Header
m_lstTable.InsertColumn(0,"灰度值",LVCFMT_LEFT,