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);
}