📄 inputwnd.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
/* 工程:手写数字识别系统 */
/* 文件: InputWnd.cpp : 实现文件 */
/* 功能:输入终端和数据处理类 */
/* 作者:陈海艺 */
/* 时间: 2004-6-23 */
/* Email:Iorikingdom@hotmail.com */
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "手写数字识别系统.h"
#include "InputWnd.h"
#include ".\inputwnd.h"
// CInputWnd
IMPLEMENT_DYNAMIC(CInputWnd, CWnd)
CInputWnd::CInputWnd()
: m_bTrain(false)
{
//背景色画刷
m_brBack.CreateSolidBrush (RGB(255,255,255));
//方块填充画刷
m_brSquare.CreateSolidBrush (RGB(255,0,0));
//网格线画刷
m_hPen.CreatePen (PS_SOLID,1,RGB(0,192,192));
m_bInitDraw=false;
//初始化输入矩阵
for(int i=0;i<LEN;i++)
for(int j=0;j<LEN;j++)
{
m_bArray[i][j]=false;
m_InputArray[i][j]=0;
}
}
CInputWnd::~CInputWnd()
{
if(m_hFile!=INVALID_HANDLE_VALUE)
{
if (m_bTrain){
OVERLAPPED Overlapped={0};
DATA d;
memcpy(d.e ,e,sizeof(E)*10);
memcpy(&(d.WE),&WE,sizeof(WEIGHT));
//把训练过的权值写回文件
::WriteFile (m_hFile,&d,sizeof(DATA),NULL,&Overlapped);
}
::CloseHandle(m_hFile);
}
}
BEGIN_MESSAGE_MAP(CInputWnd, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()
void CInputWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
//重绘信息
DrawInputWnd(&dc);
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CWnd::OnPaint()
}
// 画出输入框架
bool CInputWnd::DrawInputWnd(CPaintDC *pDC)
{
CBrush *pOldBr=pDC->SelectObject (&m_brBack);
float sizeHeight=0.0;
float sizeWidth=0.0;
float newsize=0.0;
this->GetClientRect(&m_rectThis);
sizeHeight=m_rectThis.Height ()/LENF;//求出方块的长
float x=0.0;
sizeWidth=m_rectThis.Width ()/LENF;//方块的宽
float y=0.0;
if(m_bInitDraw==false){ //看方块是否已经被写上
for(int i=0;i<LEN;i++)
{
for(int j=0;j<LEN;j++)
{
m_rectArray[i][j].left =x;
m_rectArray[i][j].right =m_rectArray[i][j].left+sizeWidth;
m_rectArray[i][j].top =y;
m_rectArray[i][j].bottom =m_rectArray[i][j].top+sizeHeight ;
y=y+sizeHeight;
}
y=0.0;
x=x+sizeWidth;
}
m_bInitDraw=true;
}
pDC->Rectangle (&m_rectThis);
pDC->SelectObject (&m_hPen);
newsize=0;
for(int i=0;i<=LEN;i++,newsize+=sizeHeight)
{
pDC->MoveTo (0,newsize);
pDC->LineTo (m_rectThis.Width (),newsize); //画背景网格
}
newsize=0;
for(int i=0;i<=LEN;newsize+=sizeWidth,i++)
{
pDC->MoveTo (newsize,0);
pDC->LineTo (newsize,m_rectThis.Height ()); //画背景网格
}
pDC->SelectObject (&m_brSquare);
for(int i=0;i<LEN;i++)
for(int j=0;j<LEN;j++)
{
if(m_bArray[i][j]==true)
pDC->Rectangle (&m_rectArray[i][j]); //填充小方块
}
pDC->SelectObject (pOldBr);
return false;
}
void CInputWnd::OnLButtonDown(UINT nFlags, CPoint point)
{
for(int i=0;i<LEN;i++)
{
for(int j=0;j<LEN;j++)
{
if(m_rectArray[i][j].PtInRect (point)&&m_bArray[i][j]==false)
{
m_bArray[i][j]=true;
this->InvalidateRect (&m_rectArray[i][j]);
break;
}
}
}
CWnd::OnLButtonDown(nFlags, point);
}
void CInputWnd::OnMouseMove(UINT nFlags, CPoint point)
{
if(nFlags==MK_LBUTTON)
{
for(int i=0;i<LEN;i++)
{
for(int j=0;j<LEN;j++)
{
if(m_rectArray[i][j].PtInRect (point)&&m_bArray[i][j]==false)
{
m_bArray[i][j]=true;
this->InvalidateRect (&m_rectArray[i][j]);
break;
}
}
}
}
CWnd::OnMouseMove(nFlags, point);
}
// 获取经过调整的输入层数值,或者样本数值
bool CInputWnd::GetInput(int index)
{
//////////////////////////////////////////////////////////////////////////////
/* 调整坐标使输入居中 */
int iLeft=LEN,iRight=0,iTop=LEN,iBottom=0;
for(int i=0;i<LEN;i++)
{
for(int j=0;j<LEN;j++)
{
if(m_bArray[i][j])
{
if (iTop>j)
iTop=j; //识别方阵的最左
if(iBottom<j)
iBottom=j; //方阵的最右
if(iLeft>i)
iLeft=i; //方阵的最上
if(iRight<i)
iRight=i; //方阵的最下
}
}
}
int xMiddle=0,yMiddle=0;
xMiddle=(iRight-iLeft)/2+1;
yMiddle=(iBottom-iTop)/2+1;
iLeft=iLeft+xMiddle; //中间点的x
iTop=iTop+yMiddle; //中间点的y
int dx=iLeft-LEN/2; //求出坐标差
int dy=iTop-LEN/2; //求出坐标差
for(int i=0;i<LEN;i++) //平移坐标
for(int j=0;j<LEN;j++)
if(m_bArray[i][j])
m_InputArray[i-dx][j-dy]=1;
for(int i=0;i<LEN;i++)
for(int j=0;j<LEN;j++)
m_bArray[i][j]=false;
for(int i=0;i<LEN;i++)
for(int j=0;j<LEN;j++)
if(m_InputArray[i][j]==1)
m_bArray[i][j]=true;
this->Invalidate ();
for(int i=0,t=0;i<LEN;i++)
for(int j=0;j<LEN;j++)
{
e[index].input[t]=(int )m_InputArray[i][j];//获取输入层的值
t++;
}
///////////////////////////////////////////////////////////////////////////
// 初始化输出端 //
if(index<10)
{
for(int i=0;i<10;i++)
e[index].output [i]=0;
for(int k=0;k<index;k++);
e[index].output [k]=1;
e[index].Figure =index;
}
/////////////////////////////////////////////////////////////////////////////
e[index].simpling =true;
{//判断是否完成采样,如果完成的话可以进入训练或者识别阶段
int i=0;
for(i=0;i<10;i++)
if(e[i].simpling==true)
continue;
else break;
if(i==10)
m_bTrain=true;
}
for(int i=0;i<LEN;i++)
for(int j=0;j<LEN;j++)
{
m_InputArray[i][j]=0;//清洁旧值
}
return false;
}
// 给输入的矩阵清零,用来下次输入
bool CInputWnd::ClearInput(void)
{
for(int i=0;i<LEN;i++)
for(int j=0;j<LEN;j++)
m_InputArray[i][j]=0;
return false;
}
// 初始化样本,如果存在文件信息从文件里面调入信息
bool CInputWnd::Initialization(void)
{
OVERLAPPED Overlapped={0};
DATA d;
//判断是否存在文件来调入信息
m_hFile=::CreateFile ("info.dat",
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if(m_hFile!=INVALID_HANDLE_VALUE)
{
if( !ReadFile(m_hFile,&d,sizeof(DATA),NULL,&Overlapped))
{//文件为空或者存在其他原因的话用默认方式来权值初始化
InitWeight();
}
m_bTrain=true;
memcpy(e ,d.e,sizeof(E)*10);
memcpy(&WE,&(d.WE ),sizeof(WEIGHT));
}
else
//说明文件不存在,所以用默认信息来初值化
{
m_hFile=::CreateFile ("info.dat",
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(m_hFile==INVALID_HANDLE_VALUE)
{
AfxMessageBox("未能够创建文件");
exit(1);
}
else
{
InitWeight();
}
}
return false;
}
// 训练函数,界面线程应该跟工作线程分开,这里为了省去麻烦,没有分开
int CInputWnd::Training(int index)
{//
float a[M],o[P];
float Err[P];
float errsum=0;
float tempsum=0;//总误差
float in_j[M];
float in_i[P];
for(;;)
//迭代到达到需要的精度
{
errsum=0;
for(int u=0;u<LEN;u++)
{
for(int j=0;j<M;j++)
{
in_j[j]=0;
for(int k=0;k<N;k++)
{
in_j[j]=in_j[j]+WE.v[k][j]*e[u].input [k];
}
a[j]=FX(in_j[j]);//求出矩阵a
}
for(int i=0;i<P;i++)
{
in_i[i]=0;
for(int j=0;j<M;j++)
{
in_i[i]=in_i[i]+WE.w[j][i]*a[j];
}
o[i]=FX(in_i[i]);//求出输出矩阵o
}
for(int i=0;i<P;i++)
{
Err[i]=e[u].output[i]-o[i];
tempsum+=Err[i]*Err[i];
}
errsum+=tempsum/2.0;//样本误差
tempsum=0;
for(int j=0;j<M;j++)//输出层误差调整
{
for(int i=0;i<P;i++)
{
WE.w[j][i]+=A*a[j]*Err[i]*DFX(in_i[i]);
}
}
float NewErr[M]; //隐层的误差
for(int j=0;j<M;j++)
{
float sum=0;
for(int i=0;i<P;i++)
{
sum+=WE.w[j][i]*DFX(in_i[i])*Err[i];
}
NewErr[j]=sum;
}
for(int k=0;k<N;k++)//隐层权值调整
{
for(int j=0;j<M;j++)
{
WE.v[k][j]+=A*e[u].input [k]*NewErr[j]*DFX(in_j[j]);
}
}
}
if(errsum<precision)
break;
}
return 0;
}
// 识别数字
RESULT CInputWnd::Identification(void)
{
float Err[P];
float a[M];
float o[P];
RESULT result;
result.result =-1;
for(int c=0;c<P;c++)
{
for(int j=0;j<M;j++)
{
float sum=0;
for(int k=0;k<N;k++)
sum+=WE.v [k][j]*e[10].input [k];
a[j]=FX(sum);
}
for(int i=0;i<P;i++)
{
float sum=0;
for(int j=0;j<M;j++)
{
sum+=WE.w [j][i]*a[j];
}
o[i]=FX(sum);
}
float errsum=0;
for(int i=0;i<P;i++)
{
Err[i]=o[i]-e[c].output [i];
errsum+=Err[i]*Err[i];
}
errsum=errsum/2.0;//求出误差
int r=0;
for(;r<P;r++)
{
//如果达到精度要求就输出
if(errsum>precision)
break;
}
if(r==P){
result.result =c;
result.error =errsum;
return result;
}
}
return result;
}
// 初始化权值
void CInputWnd::InitWeight(void)
{
//伪随机种子
srand((unsigned)time( NULL ) );
for(int i=0;i<M;i++)
for(int j=0;j<P;j++)
{
//给隐层权值赋伪随机值
float rnd;
rnd=(rand()%100)/100.0;
WE.w [i][j]= rnd;//权值初始化。
}
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
{
//给输出层权值赋伪随机值
float rnd;
rnd=(rand()%100)/100.0;
WE.v [i][j]= rnd;//权值初始化。
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -