www.pudn.com > VQ_Final.rar > Step1.cpp


// Step1.cpp : implementation file 
// 
 
#include "afxwin.h" 
#include "afxctl.h" 
#include "resource.h" 
#include "Step1.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
UINT Train(LPVOID ptr); 
///////////////////////////////////////////////////////////////////////////// 
// CStep1 property page 
 
IMPLEMENT_DYNCREATE(CStep1, CPropertyPage) 
 
CStep1::CStep1() : CPropertyPage(CStep1::IDD) 
{ 
	//{{AFX_DATA_INIT(CStep1) 
	//}}AFX_DATA_INIT 
} 
 
CStep1::~CStep1() 
{ 
} 
 
void CStep1::DoDataExchange(CDataExchange* pDX) 
{ 
	CPropertyPage::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CStep1) 
	DDX_Control(pDX, IDC_TIME, m_edTime); 
	DDX_Control(pDX, IDC_THRESHOLD, m_edThreshold); 
	DDX_Control(pDX, IDC_PROMPT, m_sPrompt); 
	DDX_Control(pDX, IDC_PROGRESS, m_prgTrain); 
	DDX_Control(pDX, IDC_VALUE, m_sValue); 
	DDX_Control(pDX, IDC_NUM, m_slNum); 
	//}}AFX_DATA_MAP 
} 
 
 
BEGIN_MESSAGE_MAP(CStep1, CPropertyPage) 
	//{{AFX_MSG_MAP(CStep1) 
	ON_BN_CLICKED(IDC_256, On256) 
	ON_BN_CLICKED(IDC_1024, On1024) 
	ON_WM_HSCROLL() 
	ON_BN_CLICKED(IDC_TRAIN, OnTrain) 
	ON_EN_CHANGE(IDC_THRESHOLD, OnChangeThreshold) 
	ON_EN_CHANGE(IDC_TIME, OnChangeTime) 
	ON_BN_CLICKED(IDC_SHOWBOOK, OnShowbook) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CStep1 message handlers 
 
BOOL CStep1::OnSetActive() //开始这一步时 
{ 
	m_slNum.SetRange(1,4,TRUE);		//用户可以选的维数,太多了效果会不好 
	 
	m_pSheet->SetWizardButtons(0);	//进度条置零 
	return CPropertyPage::OnSetActive(); 
} 
 
void CStep1::On256()  
{ 
	m_nVectors=256;	 
} 
 
void CStep1::On1024()  
{ 
	m_nVectors=1024;	 
} 
 
void CStep1::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)  
{ 
	CString t; 
	m_nPoints1=m_slNum.GetPos(); 
	t.Format("%dX%d",m_nPoints1,m_nPoints1); 
	m_pSheet->m_nPoints1=this->m_nPoints1; 
	m_pSheet->m_nPoints=this->m_nPoints=m_nPoints1*m_nPoints1; 
	m_sValue.SetWindowText(t); 
	CPropertyPage::OnHScroll(nSBCode, nPos, pScrollBar); 
} 
 
void CStep1::OnTrain() //开始训练 
{ 
	//以下为确认用户选择了初始条件 
	if (m_nVectors==0) 
	{ 
		AfxMessageBox("请选择码本中向量的个数!"); 
		return; 
	} 
	if (m_nPoints==0) 
	{ 
		AfxMessageBox("请选择向量的维数!"); 
		return; 
	} 
	if (m_nThreshold==0) 
	{ 
		AfxMessageBox("请选择噪声门限!"); 
		return; 
	} 
	if (m_nTime==0) 
	{ 
		AfxMessageBox("请选择最多训练的次数!"); 
		return; 
	} 
	m_prgTrain.SetRange(0,100); 
	m_prgTrain.SetPos(0); 
		 
	//以下让用户选择输出的码本文件 
	char szFilters[]="码本文件 (*.txt)|*.txt|"; 
	CString t; 
	t=m_pSheet->m_sTitle+"的码本.txt"; 
	CFileDialog dlg(FALSE,"txt",t,OFN_HIDEREADONLY,szFilters,this); 
	 
	if( dlg.DoModal()==IDOK) 
	{ 
		m_pSheet->m_sCodeBook = dlg.GetPathName(); 
		m_pSheet->m_nVectors=this->m_nVectors; 
		m_pSheet->m_nVectors=this->m_nVectors; 
		GetDlgItem(IDC_TRAIN)->EnableWindow(FALSE); 
		//启动训练线程 
		m_pThread=AfxBeginThread(Train,(LPVOID)this,THREAD_PRIORITY_NORMAL,0,0,NULL);	 
    } 
	 
} 
BOOL CStep1::OnQueryCancel() //当用户点了“取消”按钮 
{ 
	if (m_pThread) 
	{ 
		m_bStopThread=TRUE; 
		m_sPrompt.SetWindowText("正在结束线程......"); 
		 
		//等待训练线程结束 
		WaitForSingleObject(m_pThread->m_hThread,1); 
	} 
	return CPropertyPage::OnQueryCancel(); 
} 
 
UINT Train(LPVOID ptr)	//训练码本,因为要作为一个线程运行,所以写成一个函数,很臃肿 
{ 
	CStep1 *pDlg=(CStep1 *)ptr;	//得到CStep1的指针 
	CFile fBmp,fBook; 
	ULONG lOffset,lBytes,lLength,lWidth,lWidth1,lHeight,lHeight1,lReal,lReal1; 
	BYTE *pOldBook; 
	UINT i,j,k,m,l,nStart,nVectors=pDlg->m_nVectors,nPoints=pDlg->m_nPoints,nPoints1=pDlg->m_nPoints1; 
	 
	pDlg->m_sPrompt.SetWindowText("正在生成初始码本......"); 
	 
	//以下读文件头 
	CFileException e; 
	if (!fBmp.Open(pDlg->m_pSheet->m_sFile,CFile::modeRead,&e)) 
	{ 
		e.ReportError(); 
		return 1; 
	} 
	fBmp.Seek(0x0a,CFile::begin); 
	fBmp.Read(&lOffset,sizeof(ULONG)); 
	fBmp.Seek(0x22,CFile::begin); 
	fBmp.Read(&lBytes,sizeof(ULONG)); 
	fBmp.Seek(0x12,CFile::begin); 
	fBmp.Read(&lWidth1,sizeof(ULONG)); 
	fBmp.Seek(0x16,CFile::begin); 
	fBmp.Read(&lHeight1,sizeof(ULONG)); 
	 
	//跳到数据开始处 
	fBmp.Seek(lOffset,CFile::begin); 
 
	//计算相关量 
	pDlg->m_pSheet->m_nReal1=lReal1=lWidth1*lHeight1*3;		//实际长度 
	lWidth=lWidth1+(lWidth1%nPoints1==0 ? 0 : nPoints1-lWidth1%nPoints1);	 
	lHeight=lHeight1+(lHeight1%nPoints1==0 ? 0  : nPoints1-lHeight1%nPoints1); 
	pDlg->m_pSheet->m_nReal=lReal=lWidth*lHeight*3; 
 
	lLength=nVectors*nPoints*3;	//码本长度 
	pDlg->m_pSheet->m_nSkip=lWidth%4;		//每行尾要跳过的字节数 
			//因为BMP文件每行的字节数要为4的倍数,不足就会补零 
	 
	pDlg->m_pSheet->m_pOrgData=new BYTE[lReal];	//为数据分配空间 
	pDlg->m_pSheet->m_pData=new BYTE[lReal];	//为数据分配空间 
	BYTE *pTemp=new BYTE[lReal1]; 
 
	for (i=0,nStart=0;im_pSheet->m_nSkip,CFile::current); 
			nStart=0; 
		} 
	} 
	fBmp.Close(); 
	//给每行每列尾补零以使宽度高度能被向量维数整除 
	for (j=0;jm_pSheet->m_pOrgData[j*lWidth*3+i*3+k]=pTemp[j*lWidth1*3+i*3+k]; 
				else 
					pDlg->m_pSheet->m_pOrgData[j*lWidth*3+i*3+k]=0; 
	 
	delete[] pTemp; 
 
	//把按行存放的数据变成按向量块存放的数据 
	for(i=0,m=0;im_pSheet->m_pData[m] 
						=pDlg->m_pSheet->m_pOrgData[i*lWidth*nPoints1*3+j*nPoints1*3+k*lWidth*3+l]; 
					m++; 
				} 
			} 
		} 
	} 
  
	pDlg->m_pSheet->m_nNum=lReal/(nPoints*3);	//量化后的向量数 
	pDlg->m_pSheet->m_pVQ=new WORD[lReal/(nPoints*3)];	//为VQ结果分配空间 
 
	//则均匀地在位图中取一些点作为初始码本 
	UINT nCurrent=0; 
	pDlg->m_pSheet->m_pBook=new BYTE[lLength]; 
	pOldBook=new BYTE[lLength]; 
 
	for(i=0;im_pSheet->m_pData[i*(pDlg->m_pSheet->m_nNum/nVectors)*nPoints*3+j]; 
	 
	//以下以LBG算法训练码本 
	UINT *pPoints=new UINT[nVectors];	//用来存每个向量组中向量的个数 
	BOOL bAgain;						//是否再训练一遍 
	UINT nTime=0;						//训练了几次 
	do									 
	{ 
		CString t; 
		t.Format("正在训练码本(第%d遍)......",nTime+1); 
		pDlg->m_sPrompt.SetWindowText(t); 
		//清空新码本 
		for (i=0;im_pSheet->m_pBook[i]=0; 
		//每个向量组的向量个个数清零 
		for (i=0;im_pSheet->m_nNum;i++) 
		{ 
			UINT nDis=INT_MAX,nTemp,nPos=0; 
			for (j=0;jm_pSheet->m_pData[i*nPoints*3+k]-pOldBook[j*nPoints*3+k])*(pDlg->m_pSheet->m_pData[i*nPoints*3+k]-pOldBook[j*nPoints*3+k]); 
 
				//这样nDis中存的是最小的距离,nPos中是对应的序号 
				if (nDis>nTemp) 
				{ 
					nDis=nTemp; 
					nPos=j; 
				} 
				//若终止线程 
				if (pDlg->m_bStopThread) 
				{ 
					delete[] pPoints; 
					delete[] pOldBook; 
					return 1; 
				} 
			} 
			//其实,若读入的向量与某个码本向量最接近,那么这个码本向量 
			//就是量化结果,所以所nPos当作量化结果存下来。也就是说这里 
			//在训练码本的同时就完成了矢量量化 
			pDlg->m_pSheet->m_pVQ[i]=nPos; 
			//改变新码本中相应向量的重心,即与读入的向量再平均 
			for (j=0;jm_pSheet->m_pBook[nPos*nPoints*3+j]= 
					(pPoints[nPos]*pDlg->m_pSheet->m_pBook[nPos*nPoints*3+j] 
					+pDlg->m_pSheet->m_pData[i*nPoints*3+j])/(pPoints[nPos]+1); 
			pPoints[nPos]++;	//该组向量的个数加1 
		 
			pDlg->m_prgTrain.SetPos(100*i/pDlg->m_pSheet->m_nNum);	//改变进度条 
			if (pDlg->m_bStopThread)		//若终止线程 
			{ 
				delete[] pPoints; 
				return 1; 
			} 
		} 
		//以下通过计算噪声来决定是否再训练 
		bAgain=FALSE; 
		UINT nDis,nTemp; 
		for (i=0,nDis=0;im_pSheet->m_pBook[i]-pOldBook[i])*(pDlg->m_pSheet->m_pBook[i]-pOldBook[i]); 
			if (nDispDlg->m_nThreshold && nTimem_nTime )	 
		{ 
			//再训练一次 
			bAgain=TRUE; 
			//把新码本的内容赋给老码本 
			for (i=0;im_pSheet->m_pBook[i]; 
				} 
	}while(bAgain); 
	//释放内存 
	delete[] pPoints; 
	delete[] pOldBook; 
 
	//以下写码本文件 
	pDlg->m_sPrompt.SetWindowText("正在写码本文件......"); 
 
	CString t; 
	if (!fBook.Open(pDlg->m_pSheet->m_sCodeBook,CFile::modeCreate|CFile::modeWrite,&e)) 
	{ 
		e.ReportError(); 
		return 1; 
	} 
	t.Format("码本项数:%d\15\12",lLength/(nPoints*3)); 
	fBook.Write(t,t.GetLength()); 
	for (i=0;im_pSheet->m_pBook[i+j*3+2], 
				pDlg->m_pSheet->m_pBook[i+j*3+1], 
				pDlg->m_pSheet->m_pBook[i+j*3]); 
			fBook.Write(t,t.GetLength()); 
			if ((j+1)%nPoints1==0) 
			{ 
				t.Format("\15\12"); 
				fBook.Write(t,t.GetLength()); 
			} 
		} 
		t.Format("\15\12"); 
		fBook.Write(t,t.GetLength()); 
	} 
	 
	pDlg->m_sPrompt.SetWindowText("码本文件已经生成。"); 
	pDlg->m_prgTrain.SetPos(100); 
	pDlg->m_pSheet->SetWizardButtons(PSWIZB_NEXT); 
	pDlg->m_slNum.EnableWindow(FALSE); 
	(CButton *)(pDlg->GetDlgItem(IDC_TRAIN))->EnableWindow(FALSE); 
	(CButton *)(pDlg->GetDlgItem(IDC_SHOWBOOK))->ShowWindow(SW_SHOW); 
	fBook.Close(); 
 
	return 0; 
	 
} 
 
 
BOOL CStep1::OnInitDialog()  
{ 
	CPropertyPage::OnInitDialog(); 
	 
	m_edThreshold.SetWindowText("100"); 
	m_edTime.SetWindowText("1"); 
			 
	return TRUE;  // return TRUE unless you set the focus to a control 
	              // EXCEPTION: OCX Property Pages should return FALSE 
} 
 
void CStep1::OnChangeThreshold()  
{ 
	CString t; 
	m_edThreshold.GetWindowText(t); 
	m_nThreshold=atoi(t); 
} 
 
void CStep1::OnChangeTime()  
{ 
	CString t; 
	m_edTime.GetWindowText(t); 
	m_nTime=atoi(t); 
	 
} 
 
void CStep1::OnShowbook()  
{ 
	CString t="notepad "; 
	t+=m_pSheet->m_sCodeBook; 
	WinExec(t,SW_SHOW);	 
}