⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imageprocessview.cpp

📁 是一种采用哈夫曼算法的图像压缩算法
💻 CPP
字号:
// ImageProcessView.cpp : implementation of the CImageProcessView class
//

#include "stdafx.h"
#include "ImageProcess.h"

#include "ImageProcessDoc.h"
#include "ImageProcessView.h"
#include "mainfrm.h"
#include "DlgHuffman.h"
#include "DlgRatio.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CImageProcessView

IMPLEMENT_DYNCREATE(CImageProcessView, CScrollView)

BEGIN_MESSAGE_MAP(CImageProcessView, CScrollView)
	//{{AFX_MSG_MAP(CImageProcessView)
	ON_COMMAND(ID_CODE_HUFFMAN, OnCodeHuffman)
	ON_COMMAND(ID_CODE_DEHUFFMAN, OnCodeDehuffman)
	//}}AFX_MSG_MAP
	// Standard printing commands
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CImageProcessView construction/destruction

CImageProcessView::CImageProcessView()
{
	// TODO: add construction code here

}

CImageProcessView::~CImageProcessView()
{
}

BOOL CImageProcessView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CScrollView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CImageProcessView drawing

void CImageProcessView::OnDraw(CDC* pDC)
{ 
	BeginWaitCursor( );

	CImageProcessDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	HDIB hDIB=pDoc->GetHDIB( );
	
	if(hDIB!=NULL)
	{ LPSTR lpDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);
   	  int cxDIB=(int)::DIBWidth(lpDIB);
	  int cyDIB=(int)::DIBHeight(lpDIB);
	  ::GlobalUnlock((HGLOBAL)hDIB);

	  CRect rcDIB;
	  rcDIB.top=rcDIB.left=0;
	  rcDIB.right=cxDIB;
 	  rcDIB.bottom=cyDIB;

	  CRect rcDest;
	  if(pDC->IsPrinting( ))
	  { int cxPage=pDC->GetDeviceCaps(HORZRES);
	    int cyPage=pDC->GetDeviceCaps(VERTRES);

	    int cxInch=pDC->GetDeviceCaps(LOGPIXELSX);
	    int cyInch=pDC->GetDeviceCaps(LOGPIXELSY);

	    rcDest.top=rcDest.left=0;
	    rcDest.bottom=(int)(((double)cyDIB *cxPage*cyInch)/((double)cxDIB*cyInch));
	    rcDest.right=cxPage;

	    int temp=cyPage-(rcDest.bottom-rcDest.top);
	    rcDest.bottom +=temp/2;
	    rcDest.top+=temp/2;
	  }
	  else
	  { rcDest=rcDIB;
	  }

	::PaintDIB(pDC->m_hDC,&rcDest,pDoc->GetHDIB( ),&rcDIB,pDoc->GetDocPalette());
	}
	EndWaitCursor( );
}

void CImageProcessView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	CSize sizeTotal;
	// TODO: calculate the total size of this view
	sizeTotal.cx = sizeTotal.cy = 100;
	SetScrollSizes(MM_TEXT, sizeTotal);
}


/////////////////////////////////////////////////////////////////////////////
// CImageProcessView diagnostics

#ifdef _DEBUG
void CImageProcessView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CImageProcessView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CImageProcessDoc* CImageProcessView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CImageProcessDoc)));
	return (CImageProcessDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CImageProcessView message handlers
BOOL CImageProcessView::OnEraseBkgnd(CDC *pDC)
{ CImageProcessDoc *pDoc=GetDocument();
  CBrush brush(pDoc->m_refColorBKG);
  CBrush *pOldBrush=pDC->SelectObject(&brush);

  CRect rectClip;
  pDC->GetClipBox(&rectClip);
   
  pDC->PatBlt(rectClip.left,rectClip.top,rectClip.Width(),rectClip.Height(),PATCOPY);
  pDC->SelectObject(pOldBrush);
  
  return TRUE;
}

LRESULT CImageProcessView::OnDoRealize(WPARAM wParam,LPARAM lParam)
{ ASSERT(wParam!=NULL);
  CImageProcessDoc *pDoc=GetDocument( );

  if(pDoc->GetHDIB()==NULL)
  { return 0L;
  }

  CPalette *pPal=pDoc->GetDocPalette();
  if(pPal!=NULL)
  { CMainFrame *pAppFrame=(CMainFrame *)AfxGetApp()->m_pMainWnd;
    ASSERT_KINDOF(CMainFrame,pAppFrame);

    CClientDC appDC(pAppFrame);
	CPalette *oldPalette=appDC.SelectPalette(pPal,((HWND)wParam)!=m_hWnd);

	if(oldPalette!=NULL)
	{ UINT nColorsChanged=appDC.RealizePalette( );
	  if(nColorsChanged>0)
		  pDoc->UpdateAllViews(NULL);
	  appDC.SelectPalette(oldPalette,TRUE);
	}
	else
	{ TRACE0("\tCImageProcessView::OnPaletteChanged中调用SelectPalette()失败!\n");
	}
  }
  return 0L;
}


void CImageProcessView::CalcWindowRect(LPRECT lpClientRect,UINT nAdjustType)
{ CScrollView::OnInitialUpdate ();
  ASSERT((GetDocument)!=NULL);

  SetScrollSizes(MM_TEXT,GetDocument()->GetDocSize());
}

void CImageProcessView::OnActivateView(BOOL bActivate,CView *pActivateView,
									   CView *pDeactiveView)
{ CScrollView::OnActivateView(bActivate,pActivateView,pDeactiveView);
  
  if(bActivate)
  { ASSERT(pActivateView==this);
    OnDoRealize((WPARAM) m_hWnd,0);
  }
}


void CImageProcessView::OnCodeHuffman() 
{
  CImageProcessDoc *pDoc=GetDocument( ); //获取文档
  BYTE * lpSrc;   //指向源图像像素的指针
  
  LPSTR lpDIB;       //指向DIB的指针
  LPSTR lpDIBBits;   //指向DIB像素的指针
  
  long lHeight;      //DIB的高度
  long lWidth;       //DIB的宽度
  long lLineBytes;   //图像每行的字节数
  long lCountSum;    //图像像素总数
  
  long i;    //循环变量
  long j;


  float *fFreq;  //保存各个灰度值频率的数组指针
  int iColorNum; //获取当前DIB颜色数目
  int ActualColorNum=0;  //获取当前DIB实际的颜色数目

  lpDIB= (LPSTR)::GlobalLock((HGLOBAL) pDoc->GetHDIB());
  if(lpDIB==NULL)
	return;
  lpDIBBits=::FindDIBBits(lpDIB);
  iColorNum=::DIBNumColors(lpDIB);
  

  //判断是否是8-bpp位图
  if(iColorNum!=256)
  { MessageBox("目前只支持256级灰度位图哈夫曼编码!","系统提示",
               MB_ICONINFORMATION | MB_OK);
    ::GlobalUnlock((HGLOBAL)pDoc->GetHDIB());
	return;
  }

  BeginWaitCursor( );

  fFreq=new float[2*iColorNum];
  lWidth=::DIBWidth(lpDIB);
  lHeight=::DIBHeight(lpDIB);
  lLineBytes=WIDTHBYTES(lWidth*8);

  for(i=0;i<iColorNum;i++)
    fFreq[i]=0.0;
  
  for(i=0;i<lHeight;i++)   //计算各个灰度值的计数
    for(j=0;j<lWidth;j++)
	{  lpSrc=(BYTE *)lpDIBBits+lLineBytes*i+j;
       fFreq[*(lpSrc)]++;
	}

  for(i=0;i<iColorNum;i++)
	  if(fFreq[i]>0)
		 ActualColorNum++;

  lCountSum=lHeight*lWidth;
  
  for(i=0;i<iColorNum;i++)    //计算各个灰度值出现的概率
     fFreq[i]/=(float)lCountSum;
  
  //计算各个灰度值出现的概率结束
  //**************************************************
  //创建对话框
  CDlgHuffman dlgPara;
  dlgPara.m_fFreq =new HuffmanTree [2*ActualColorNum];
  int temp=1;
  for(i=1;i<=iColorNum;i++)
    if(fFreq[i-1]>0)
	  {  dlgPara.m_fFreq[temp].freq=fFreq[i-1];
	     dlgPara.m_fFreq[temp].GrayValue=i-1;
		 temp++;
	  }
  for(i=0;i<=2*ActualColorNum;i++)
	{ dlgPara.m_fFreq[i].lchild =0;
	  dlgPara.m_fFreq[i].rchild =0;
	  dlgPara.m_fFreq[i].parent =0;
	}
  for(i=ActualColorNum+1;i<2*ActualColorNum;i++)
      dlgPara.m_fFreq[i].freq =0.0;
  dlgPara.m_iColorNum=ActualColorNum;
  dlgPara.m_height=(unsigned int)lHeight;
  dlgPara.m_width=(unsigned int)lWidth;
  dlgPara.m_lpDIB=lpDIB;
  dlgPara.m_lpDIBBits=lpDIBBits;
  dlgPara.m_lLineBytes=lLineBytes;
  
  dlgPara.DoModal();
 
  //以下对图象进行编码并存入文件
   
   char szFilters[]="*.huf";//选择需要写入的文件
   CString PathName;   //选择文件的路径
   CFile ImageFile;    //文件对象
   unsigned int p,q,k;
   HUFHEADER hufHdr;   //以下为准备写入的*.huf文件头
   hufHdr.wManufacturer =HUF_HEADER_MARKER;
   hufHdr.bVersion =0x0001;
   hufHdr.wHeight =dlgPara.m_height;
   hufHdr.wWidth =dlgPara.m_width;
   hufHdr.wItemNum =2*dlgPara.m_iColorNum;
   hufHdr.wReserved =0x0000;
   
   HUFCODEBOOK *hufCodeBk;
   hufCodeBk=new HUFCODEBOOK [2*dlgPara.m_iColorNum];//以下为编码本的准备
   for(p=0;p<2*dlgPara.m_iColorNum;p++)
   { hufCodeBk[p].GrayValue =dlgPara.m_fFreq[p].GrayValue ;
     hufCodeBk[p].lchild=dlgPara.m_fFreq[p].lchild ;
	 hufCodeBk[p].rchild=dlgPara.m_fFreq[p].rchild ;
	 hufCodeBk[p].parent=dlgPara.m_fFreq[p].parent ;
   }
   hufHdr.wSize=hufHdr.wItemNum *sizeof(HUFCODEBOOK);

   int LeftBits=0;  //记载没有编码的位数
   int bits=0;  
   unsigned int m;
   BYTE wCode=0x00;
   WORD tempCode=0x0000;
   CFileDialog dlgFileSave(FALSE,"huf","*.huf",
	                       OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT,szFilters,this);
   if(dlgFileSave.DoModal ()==IDOK)
     PathName=dlgFileSave.GetPathName();
   else  
	 return;
   TRY
   { CFile ImageFile;
     CFileException fe;
     
     ImageFile.Open(PathName,CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive,&fe);
     ImageFile.Write(&hufHdr,sizeof(HUFHEADER));//写入文件头
	 ImageFile.Write(hufCodeBk,hufHdr.wSize);  //写入编码本
	 for(q=0;q<dlgPara.m_height;q++)
		for(k=0;k<dlgPara.m_width;k++)
		{ for(p=1;p<=dlgPara.m_iColorNum;p++)
			{ lpSrc=(BYTE *)dlgPara.m_lpDIBBits+dlgPara.m_lLineBytes*q+k;
			  if(dlgPara.m_fFreq[p].GrayValue==(*lpSrc))
				break;
			}
		  	   
		  for(m=0;m<(unsigned int)(dlgPara.m_strCode[p-1].GetLength());m++)
		  { 
            wCode<<=1;
			wCode|=(dlgPara.m_strCode[p-1].GetAt(m)-'0');
			LeftBits++;
		    if(LeftBits>=8)
			{ ImageFile.Write(&wCode,1);
		      LeftBits-=8;
			  wCode=0x00;
			}
		  }
		  
		}
     for(;LeftBits<8;LeftBits++)
        wCode<<=1;
     ImageFile.Write(&wCode,1);
	 ImageFile.Close();
   }
   CATCH(CFileException,fe)
   { 
     MessageBox("Open file error!");
	 fe->Delete( );
	 return;
   }
   END_CATCH
   delete hufCodeBk;
  ::GlobalUnlock((HGLOBAL)pDoc->GetHDIB());
   
  EndWaitCursor();
 
}



void CImageProcessView::OnCodeDehuffman() 
{
  CFile hufFile,bmpSourceFile;
  CFileException fe;
  char Filters[]="*.huf";
  CString PathName;
  
  //打开欲解码的文件
  CFileDialog dlgFileDeCode(TRUE,"huf","*.huf",OFN_READONLY,Filters,this);
  if(dlgFileDeCode.DoModal ()==IDOK)
     PathName=dlgFileDeCode.GetPathName();
  else 
	 return;
  hufFile.Open((LPCTSTR)PathName,CFile::modeRead,&fe);	
  
  //打开与解码文件对应的源位图文件
  char FiltersSource[]="*.bmp";
  CFileDialog dlgFileSource(TRUE,"bmp","*.bmp",OFN_READONLY,FiltersSource,this);
  if(dlgFileSource.DoModal ()==IDOK)
     PathName=dlgFileSource.GetPathName();
  else
	 return;
  bmpSourceFile.Open((LPCTSTR)PathName,CFile::modeRead,&fe);

  HUFHEADER hufHdr;
  HUFCODEBOOK *hufCodeBk;
  DWORD  dwDIBSize;
  DWORD dwLineBytes;
  
  //读出文件头
  if(hufFile.Read(&hufHdr,sizeof(HUFHEADER))!=sizeof(HUFHEADER))
  { MessageBox("读文件发生错误,操作不能继续","提示信息",MB_OK);
    return;
  }
  //判断是否是*.huf文件
  if(hufHdr.wManufacturer!=HUF_HEADER_MARKER)
  { MessageBox("不支持此种文件格式!","提示信息",MB_OK);
    return;
  }
  
  //读入编码本
  hufCodeBk=new HUFCODEBOOK [hufHdr.wItemNum];

  if(hufFile.Read((LPSTR)hufCodeBk,hufHdr.wSize)!=hufHdr.wSize )
  { MessageBox("读文件发生错误,解码无法继续!","提示信息",MB_OK);
    return;
  }
  
  //读入像素值的编码
  BYTE *lpSrc;
  lpSrc=new BYTE [hufFile.GetLength()-sizeof(HUFHEADER)-hufHdr.wSize];
  if(hufFile.ReadHuge(lpSrc,hufFile.GetLength()
	 -sizeof(HUFHEADER)-hufHdr.wSize)!=hufFile.GetLength()
	 -sizeof(HUFHEADER)-hufHdr.wSize)
  { MessageBox("读取像素时发生错误,解码不能继续!","提示信息",MB_OK);
    return;
  }

  HDIB hDIB,hDIBSource;
  LPSTR lpDIB,lpDIBSource;
  LPBITMAPINFOHEADER lpBI;
 
  dwLineBytes=WIDTHBYTES(hufHdr.wWidth*8);
  dwDIBSize=sizeof(BITMAPINFOHEADER)+1024+hufHdr.wHeight*dwLineBytes;
  hDIB=(HDIB)::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,dwDIBSize);
  if(hDIB==0)
  { MessageBox("内存分配失败,解码无法继续!","提示信息",MB_OK);
    return;
  }
  lpDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);
  
  lpBI=(LPBITMAPINFOHEADER)lpDIB;
  lpBI->biSize =40;
  lpBI->biWidth =hufHdr.wWidth ;
  lpBI->biHeight =hufHdr.wHeight ;
  lpBI->biPlanes =1;
  lpBI->biBitCount =8;
  lpBI->biCompression =BI_RGB;
  lpBI->biSizeImage =hufHdr.wHeight * dwLineBytes;
  lpBI->biXPelsPerMeter =hufHdr.wWidth ;
  lpBI->biYPelsPerMeter =hufHdr.wHeight ;
  lpBI->biClrImportant =0;
  lpBI->biClrUsed =256 ;
  
  BYTE *lpDst,*lpSource;
  BYTE tempCode=*lpSrc;
  BYTE *lptemp;
  BYTE test=0x80;
  unsigned int i,j,LeftBits=8;   //计数变量
  
  lpDst=(BYTE *)lpDIB+sizeof(BITMAPINFOHEADER);
  for(i=0;i<256;i++)
  { for(j=0;j<3;j++,lpDst++)
      *lpDst=(BYTE)i;
    *lpDst=0x00;
	lpDst++;
  }
  lpDst=(BYTE *)FindDIBBits(lpDIB);
  
  //以下开始解码
  for(i=0;i<hufHdr.wHeight;i++)
	for(j=0;j<hufHdr.wWidth;j++)
	{ lptemp=lpDst+i*dwLineBytes+j;
	  HUFCODEBOOK tempCodeBk;
	  tempCodeBk=hufCodeBk[hufHdr.wItemNum-1];
	  while(tempCodeBk.lchild!=0 && tempCodeBk.rchild!=0)
	  { if((tempCode & test)==128)
	      tempCodeBk=hufCodeBk[tempCodeBk.rchild];
	    else
		  tempCodeBk=hufCodeBk[tempCodeBk.lchild];
		          
		LeftBits--;
		tempCode<<=1;
		if(LeftBits==0)
		{ LeftBits=8;
		  lpSrc++;
		  tempCode=*lpSrc;
		}
	  }
	  *lptemp=(BYTE)tempCodeBk.GrayValue ;
	}
    
	hDIBSource=::ReadDIBFile(bmpSourceFile);
	lpDIBSource=(LPSTR)::GlobalLock((HGLOBAL)hDIBSource);
    lpSource=(BYTE *)FindDIBBits(lpDIBSource);
	double difference=0.0;
	lptemp=lpDst;
	BYTE *lpSourcetemp=lpSource;
	for(i=0;i<hufHdr.wHeight;i++)
	  for(j=0;j<hufHdr.wWidth;j++)
	  { lptemp=lpDst+i*dwLineBytes+j;
	    lpSourcetemp=lpSource+i*dwLineBytes+j;
		difference+=pow((double)((*lptemp)-(*lpSourcetemp)),double(2));
	    if(difference!=0)
		{ i++;
	      i--;
		}
	  }
	
	//在文档中显示位图
	CImageProcessDoc *pDoc=GetDocument();
	//ASSERT_VALID(pDoc);
	pDoc->ReplaceHDIB(hDIB);
	pDoc->InitDIBData();
	//pDoc->SetModifiedFlag(TRUE);
	SetScrollSizes(MM_TEXT,pDoc->GetDocSize());
	OnDoRealize((WPARAM)m_hWnd,0);
	pDoc->UpdateAllViews(NULL);
    
	//计算峰值信噪比

	char *diffstr,*position='\0',*bitnum="000000";
	double ratio;
	int  decimal,sign;
    int  precision = 10;

	if(difference==0.0)
	{ diffstr = _ecvt( difference, precision, &decimal, &sign );
	  MessageBox(diffstr,"所有对应像素值差平方之和D",MB_OK);
	}
	else 
	{ double temp=255*255*(double)hufHdr.wHeight*(double)hufHdr.wWidth;
	  ratio=10 * log10((double)(temp/difference));
	  DlgRatio dlgra;
	  dlgra.m_dRatio =ratio;
	  dlgra.DoModal ();
	}
	
    

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -