Bp.h
上传用户:kennygump
上传日期:2022-07-22
资源大小:347k
文件大小:19k
源码类别:

图形/文字识别

开发平台:

Visual C++

  1. #include <stdio.h>
  2. #include <math.h> 
  3. #include <time.h>
  4. #include <stdlib.h>
  5. #define BIGRND 32767
  6. double drnd();
  7. double dpn1();
  8. double squash(double x);
  9. double *alloc_1d_dbl(int n);
  10. double *alloc_1d_dbl(int n);
  11. double **alloc_2d_dbl(int m, int n);
  12. void bpnn_initialize(int seed);
  13. void bpnn_randomize_weights(double **w, int m, int n);
  14. void bpnn_zero_weights(double **w, int m, int n);
  15. void bpnn_layerforward(double *l1, double *l2, double **conn, int n1, int n2);
  16. void bpnn_output_error(double *delta, double *target, double *output, int nj);
  17. void bpnn_hidden_error(double* delta_h, int nh, double *delta_o, int no, double **who, double *hidden);
  18. void bpnn_adjust_weights(double *delta, int ndelta, double *ly, int nly, double** w, double **oldw, double eta, double momentum);
  19. void w_weight(double **w,int n1,int n2,char*name);
  20. bool r_weight(double **w,int n1,int n2,char *name);
  21. void w_num(int n1,int n2,int n3,char*name);
  22. bool r_num(int *n,char *name);
  23. void code(BYTE*image ,int *p,int w,int h,int dw);
  24. void BpTrain(HDIB hDIB,int n_hidden,double min_ex,double momentum,double eta ,int width,int height);
  25. void CodeRecognize(HDIB hDIB,int width ,int height ,int n_in ,int n_hidden,int n_out);
  26. /*** 返回0-1的双精度随机数 ***/
  27. double drnd()
  28. {
  29. return ((double) rand() / (double) BIGRND);
  30. }
  31. /*** 返回-1.0到1.0之间的双精度随机数 ***/
  32. double dpn1()
  33. {
  34. return ((drnd() * 2.0) - 1.0);
  35. }
  36. double squash(double x)
  37. {
  38. return (1.0 / (1.0 + exp(-x)));
  39. }
  40. /*** 申请1维双精度实数数组 ***/
  41. double *alloc_1d_dbl(int n)
  42. {
  43. double *new1;
  44. new1 = (double *) malloc ((unsigned) (n * sizeof (double)));
  45. if (new1 == NULL) {
  46. printf("ALLOC_1D_DBL: Couldn't allocate array of doublesn");
  47. return (NULL);
  48. }
  49. return (new1);
  50. }
  51. /*** 申请2维双精度实数数组 ***/
  52. double **alloc_2d_dbl(int m, int n)
  53. {
  54. int i;
  55. double **new1;
  56. new1 = (double **) malloc ((unsigned) (m * sizeof (double *)));
  57. if (new1 == NULL) {
  58. // printf("ALLOC_2D_DBL: Couldn't allocate array of dbl ptrsn");
  59. return (NULL);
  60. }
  61. for (i = 0; i < m; i++) {
  62. new1[i] = alloc_1d_dbl(n);
  63. }
  64. return (new1);
  65. }
  66. /*** 设置随机数种子 ***/
  67. void bpnn_initialize(int seed)
  68. {
  69. //printf("Random number generator seed: %dn", seed);
  70. srand(seed);
  71. }
  72. /*** 随机初始化权值 ***/
  73. void bpnn_randomize_weights(double **w, int m, int n)
  74. {
  75. int i, j;
  76. for (i = 0; i <= m; i++) {
  77. for (j = 0; j <= n; j++) {
  78. w[i][j] = dpn1();
  79. }
  80. }
  81. }
  82. /*** 0初始化权值 ***/
  83. void bpnn_zero_weights(double **w, int m, int n)
  84. {
  85. int i, j;
  86. for (i = 0; i <= m; i++) {
  87. for (j = 0; j <= n; j++) {
  88. w[i][j] = 0.0;
  89. }
  90. }
  91. }
  92. /*********前向传输*********/
  93. void bpnn_layerforward(double *l1, double *l2, double **conn, int n1, int n2)
  94. {
  95. double sum;
  96. int j, k;
  97. /*** 设置阈值 ***/
  98. l1[0] = 1.0;
  99. /*** 对于第二层的每个神经元 ***/
  100. for (j = 1; j <= n2; j++) {
  101. /*** 计算输入的加权总和 ***/
  102. sum = 0.0;
  103. for (k = 0; k <= n1; k++) {
  104. sum += conn[k][j] * l1[k];
  105. }
  106. l2[j] = squash(sum);
  107. }
  108. }
  109. /* 输出误差 */
  110. void bpnn_output_error(double *delta, double *target, double *output, int nj)
  111. {
  112. int j;
  113. double o, t, errsum;
  114. errsum = 0.0;
  115. for (j = 1; j <= nj; j++) {
  116. o = output[j];
  117. t = target[j];
  118. delta[j] = o * (1.0 - o) * (t - o);
  119. }
  120. }
  121. /* 隐含层误差 */
  122. void bpnn_hidden_error(double* delta_h, int nh, double *delta_o, int no, double **who, double *hidden)
  123. {
  124. int j, k;
  125. double h, sum, errsum;
  126. errsum = 0.0;
  127. for (j = 1; j <= nh; j++) {
  128. h = hidden[j];
  129. sum = 0.0;
  130. for (k = 1; k <= no; k++) {
  131. sum += delta_o[k] * who[j][k];
  132. }
  133. delta_h[j] = h * (1.0 - h) * sum;
  134. }
  135. }
  136. /* 调整权值 */
  137. void bpnn_adjust_weights(double *delta, int ndelta, double *ly, int nly, double** w, double **oldw, double eta, double momentum)
  138. {
  139. double new_dw;
  140. int k, j;
  141. ly[0] = 1.0;
  142. for (j = 1; j <= ndelta; j++) {
  143. for (k = 0; k <= nly; k++) {
  144. new_dw = ((eta * delta[j] * ly[k]) + (momentum * oldw[k][j]));
  145. w[k][j] += new_dw;
  146. oldw[k][j] = new_dw;
  147. }
  148. }
  149. }
  150. /*******保存权值**********/
  151. void w_weight(double **w,int n1,int n2,char*name)
  152. {
  153. int i,j;
  154. double *buffer;
  155. FILE *fp;
  156. fp=fopen(name,"wb+");
  157. buffer=(double*)malloc((n1+1)*(n2+1)*sizeof(double));
  158. for(i=0;i<=n1;i++)
  159. {
  160. for(j=0;j<=n2;j++)
  161. buffer[i*(n2+1)+j]=w[i][j];
  162. }
  163. fwrite((char*)buffer,sizeof(double),(n1+1)*(n2+1),fp);
  164. fclose(fp);
  165. free(buffer);
  166. }
  167. /************读取权值*************/
  168. bool  r_weight(double **w,int n1,int n2,char *name)
  169. {
  170. int i,j;
  171. double *buffer;
  172. FILE *fp;
  173. if((fp=fopen(name,"rb"))==NULL)
  174. {
  175. ::MessageBox(NULL,"无法读取权值信息",NULL,MB_ICONSTOP);
  176. return (false);
  177. }
  178. buffer=(double*)malloc((n1+1)*(n2+1)*sizeof(double));
  179. fread((char*)buffer,sizeof(double),(n1+1)*(n2+1),fp);
  180. for(i=0;i<=n1;i++)
  181. {
  182. for(j=0;j<=n2;j++)
  183. w[i][j]=buffer[i*(n2+1)+j];
  184. }
  185. fclose(fp);
  186. free(buffer);
  187. return(true);
  188. }
  189. /*****保存各层结点的数目******/
  190. void w_num(int n1,int n2,int n3,char*name)
  191. {
  192. FILE *fp;
  193. fp=fopen(name,"wb+");
  194. int *buffer;
  195. buffer=(int*)malloc(3*sizeof(int));
  196. buffer[0]=n1;
  197. buffer[1]=n2;
  198. buffer[2]=n3;
  199. fwrite((char*)buffer,sizeof(int),3,fp);
  200. fclose(fp);
  201. free(buffer);
  202. }
  203. /********读取各层结点数目*********/
  204. bool r_num(int *n,char *name)
  205. {
  206. int *buffer;
  207. FILE *fp;
  208. buffer=(int *)malloc(3*sizeof(int));
  209. if((fp=fopen(name,"rb"))==NULL)
  210. {
  211. ::MessageBox(NULL,"结点参数",NULL,MB_ICONSTOP);
  212. return (false);
  213. }
  214. fread((char*)buffer,sizeof(int),3,fp);
  215. n[0]=buffer[0];
  216. n[1]=buffer[1];
  217. n[2]=buffer[2];
  218. fclose(fp);
  219. free(buffer);
  220. return(true);
  221. }
  222. /********************************************************
  223. * 函数名称 VerticalCode()
  224. *
  225. * 参量:
  226. *   BYTE* lpDIBBits   -指向输入图像的象素其实位置的指针 
  227. *   int  num          -图片中样本的个数
  228. *   LONG lLineByte    -输入图片每行的字节数
  229. *   LONG lSwidth      -预处理时归一化的宽度
  230. *   LONG lSheight     -预处理时归一化的长度
  231. *
  232. * 返回值:
  233. *   double**           -特征向量矩阵
  234. *
  235. *  函数功能 :
  236. *      对于输入样本提取特征向量,在这里把归一化样本的
  237. *    水平和竖直方向的统计特征作为特征提取出来
  238. ***************************************************************/
  239. double** VerticalCode(BYTE* lpDIBBits,int num, LONG lLineByte,LONG lSwidth,LONG lSheight)
  240. {   
  241.    //循环变量
  242.     int i,j,k;
  243.     BYTE* lpSrc; 
  244.     
  245. //统计变量
  246. int sum;
  247.     //  建立保存特征向量的二维数组
  248.    double **data;
  249.    
  250.    // 为这个数组申请二维存储空间
  251.    data = alloc_2d_dbl(num,lSwidth+lSheight);
  252.  
  253.    // 将归一化的样本的每个象素作为一个特征点提取出来
  254.    //逐个数据扫描
  255.    for(k=0;k<num;k++)  
  256.    { 
  257.      //统计每行的象素点个数
  258.       for(i=0;i<lSheight;i++)
  259.   {    
  260.         //对统计变量初始化
  261.     sum=0;
  262.           //对每个数据逐列扫描
  263.           for(j=k*lSwidth;j<(k+1)*lSwidth;j++)
  264.   {
  265.             // 指向图像第i行第j列个象素的指针
  266.             lpSrc = lpDIBBits + i*lLineByte + j;
  267.              //如果这个象素是黑色的
  268.              if(*(lpSrc)==0)
  269.              //统计变量加1
  270.                 sum++;
  271.   }
  272.          data[k][i]=sum;
  273.   }
  274.     //统计每列的象素点个数
  275.     for(j=k*lSwidth;j<(k+1)*lSwidth;j++)
  276. {    
  277.         //对统计变量初始化
  278.     sum=0;
  279.           //对每个数据逐行扫描
  280.          for(i=0;i<lSheight;i++)
  281.           {
  282.             // 指向图像第i行第j列个象素的指针
  283.             lpSrc = lpDIBBits + i*lLineByte + j;
  284.              //如果这个象素是黑色的
  285.              if(*(lpSrc)==0)
  286.              //统计变量加1
  287.                 sum++;
  288.   }
  289.          data[k][j-k*lSwidth+lSheight]=sum;
  290.   }
  291.    }
  292.  
  293. //返回特征向量矩阵
  294.    return(data);  
  295. }
  296. /*******************************************************************
  297. *
  298. *函数名称:
  299. * TZTQ_13
  300. *参数:
  301. * HDIB hDIB -待提取特征的位图的句柄
  302. * int num -字符的数目
  303. * int dim -提取特征的维数。这里固定为13
  304. *说明:
  305. * 图像分为8块,作为8个特征;象素总数作为一个特征;水平切割过去两条线,得*到两个特征;垂直的两个,总共得到13个特征
  306. *
  307. *********************************************************************/
  308. double * * TZTQ_13(HDIB hDIB,int num,int dim)
  309. {
  310. int i,j,k,m;
  311. //分配一个内存空间并得到二维指针
  312. double * * tezheng=alloc_2d_dbl(num,dim);
  313. //锁定图像句柄并获取其指针
  314. BYTE* lpDIB=(BYTE*)::GlobalLock ((HGLOBAL)hDIB);
  315. //取得图像象素数据区的起始地址
  316. BYTE* lpDIBBits=(BYTE*)::FindDIBBits((char*)lpDIB);
  317. BYTE* lpSrc;
  318. //获取图像高度
  319. LONG lHeight=::DIBHeight ((char*)lpDIB);
  320. //获取图像宽度
  321. LONG lWidth=::DIBWidth ((char*)lpDIB);
  322. LONG width=lWidth/num;
  323. //每行的字节数
  324. LONG lLineBytes = WIDTHBYTES(lWidth * 8);
  325. int b;
  326. //存储临时的特征
  327. double * tz=new double[dim];
  328. for(k=0;k<num;k++)
  329. {
  330. for(i=0;i<dim;i++) tz[i]=0;
  331. //提取前8个特征
  332. for(m=0;m<8;m++)
  333. { for(i=int(m/2)*8;i<(int(m/2)+1)*8;i++)
  334. for(j=m%2*8+k*width;j<(m%2+1)*8+k*width;j++)
  335. { lpSrc=(unsigned char*)lpDIBBits + lLineBytes *  i + j;
  336. b=(*lpSrc==255)?0:1;
  337.     tz[m]+=b;
  338. }
  339. }
  340. //提取第9个特征-总象素值
  341. for(i=0;i<lHeight;i++)
  342. for(j=k*width;j<(k+1)*width;j++)
  343. { lpSrc=(unsigned char*)lpDIBBits + lLineBytes *  i + j;
  344. b=(*lpSrc==255)?0:1;
  345.     tz[8]+=b;
  346. }
  347. //提取第10、11个特征-水平扫描切割
  348. i=int(lHeight*1/3);
  349. for(j=k*width;j<(k+1)*width;j++)
  350. { lpSrc=(unsigned char*)lpDIBBits + lLineBytes *  i + j;
  351. b=(*lpSrc==255)?0:1;
  352.     tz[9]+=b;
  353. }
  354. //
  355. i=int(lHeight*2/3);
  356. for(j=k*width;j<(k+1)*width;j++)
  357. { lpSrc=(unsigned char*)lpDIBBits + lLineBytes *  i + j;
  358. b=(*lpSrc==255)?0:1;
  359.     tz[10]+=b;
  360. }
  361. //提取第12、13个特征-垂直扫描切割
  362. j=int(k*width+width*1/3);
  363. for(i=0;i<lHeight;i++)
  364. { lpSrc=(unsigned char*)lpDIBBits + lLineBytes *  i + j;
  365. b=(*lpSrc==255)?0:1;
  366.     tz[11]+=b;
  367. }
  368. j=int(k*width+width*2/3);
  369. for(i=0;i<lHeight;i++)
  370. { lpSrc=(unsigned char*)lpDIBBits + lLineBytes *  i + j;
  371. b=(*lpSrc==255)?0:1;
  372.     tz[12]+=b;
  373. }
  374. //存储特征
  375. for(i=0;i<dim;i++)
  376. tezheng[k][i]=tz[i];
  377. }
  378. ::GlobalUnlock ((HGLOBAL)hDIB);
  379. //返回特征向量矩阵的指针
  380. return tezheng;
  381. }
  382. /**********************************
  383. * 函数名称 code()
  384. *
  385. * 参量:
  386. *   BYTE* lpDIBBits   -指向输入图像的象素其实位置的指针 
  387. *   int num           -图片中样本的个数
  388. *   LONG lLineByte    -输入图片每行的字节数
  389. *   LONG lSwidth      -预处理时归一化的宽度
  390. *   LONG lSheight     -预处理时归一化的长度
  391. *
  392. *  函数功能 :
  393. *      对于输入样本提取特征向量,在这里把归一化样本的
  394. *    每一个象素都作为特征提取出来
  395. **************************************/
  396. double** code (BYTE* lpDIBBits,int num, LONG lLineByte,LONG lSwidth,LONG lSheight)
  397. {   
  398. //循环变量
  399.     int i,j,k;
  400.     BYTE* lpSrc; 
  401.     //  建立保存特征向量的二维数组
  402. double **data;
  403. // 为这个数组申请二维存储空间
  404. data = alloc_2d_dbl(num,lSwidth*lSheight);
  405. // 将归一化的样本的每个象素作为一个特征点提取出来
  406. //逐个数据扫描
  407. for(k=0;k<num;k++)  
  408. //对每个数据逐行扫描
  409. for(i=0;i<lSheight;i++)
  410. {  
  411. //对每个数据逐列扫描
  412. for(j=k*lSwidth;j<(k+1)*lSwidth;j++)
  413. {
  414. // 指向图像第i行第j列个象素的指针
  415. lpSrc = lpDIBBits + i*lLineByte + j;
  416. //如果这个象素是黑色的
  417. if(*(lpSrc)==0)
  418. //将特征向量的相应位置填1
  419. data[k][i*lSwidth+j-k*lSwidth]=1;
  420. //如果这个象素是其他的   
  421. if(*(lpSrc)!=0)
  422. //将特征向量的相应位置填0
  423. data[k][i*lSwidth+j-k*lSwidth]=0;
  424. }
  425. }
  426. }
  427. return(data);  
  428. }
  429. /****************************************************
  430. * 函数名称 BpTrain()
  431. * 参数:
  432. *   double **data_in    -指向输入的特征向量数组的指针    
  433. * double **data_out   -指向理想输出数组的指针
  434. int n_in            -输入层结点的个数 
  435. *   int n_hidden        -BP网络隐层结点的数目
  436. *   double min_ex       -训练时允许的最大均方误差
  437. *   double momentum     -BP网络的相关系数
  438. *   double eta          -BP网络的训练步长
  439. *   int num             -输入样本的个数
  440. *
  441. * 函数功能:
  442. *     根据输入的特征向量和期望的理想输出对BP网络尽行训练
  443. *     训练结束后将权值保存并将训练的结果显示出来
  444. ********************************************************/
  445. void BpTrain(double ** data_in, double** data_out,int n_in,int n_hidden,double min_ex,double momentum,double eta ,int num)
  446. {
  447. //循环变量   
  448. int i,k,l;
  449. //输出层结点数目
  450. int  n_out=4;   
  451. //指向输入层数据的指针
  452. double* input_unites; 
  453. //指向隐层数据的指针
  454. double* hidden_unites;
  455. //指向输出层数据的指针
  456. double* output_unites; 
  457. //指向隐层误差数据的指针
  458. double* hidden_deltas;
  459. //指向输出层误差数剧的指针
  460. double* output_deltas;  
  461. //指向理想目标输出的指针
  462. double* target;    
  463. //指向输入层于隐层之间权值的指针
  464. double** input_weights;
  465. //指向隐层与输出层之间的权值的指针
  466. double** hidden_weights;
  467. //指向上一此输入层于隐层之间权值的指针
  468. double** input_prev_weights ;
  469. //指向上一此隐层与输出层之间的权值的指针
  470. double** hidden_prev_weights;
  471. //每次循环后的均方误差误差值 
  472. double ex;
  473. //为各个数据结构申请内存空间
  474. input_unites= alloc_1d_dbl(n_in + 1);
  475. hidden_unites=alloc_1d_dbl(n_hidden + 1);
  476. output_unites=alloc_1d_dbl(n_out + 1);
  477. hidden_deltas = alloc_1d_dbl(n_hidden + 1);
  478. output_deltas = alloc_1d_dbl(n_out + 1);
  479. target = alloc_1d_dbl(n_out + 1);
  480. input_weights=alloc_2d_dbl(n_in + 1, n_hidden + 1);
  481. input_prev_weights = alloc_2d_dbl(n_in + 1, n_hidden + 1);
  482. hidden_prev_weights = alloc_2d_dbl(n_hidden + 1, n_out + 1);
  483. hidden_weights = alloc_2d_dbl(n_hidden + 1, n_out + 1);
  484. //为产生随机序列撒种
  485. time_t t; 
  486. bpnn_initialize((unsigned)time(&t));
  487. //对各种权值进行初始化初始化
  488. bpnn_randomize_weights( input_weights,n_in,n_hidden);
  489. bpnn_randomize_weights( hidden_weights,n_hidden,n_out);
  490. bpnn_zero_weights(input_prev_weights, n_in,n_hidden );
  491. bpnn_zero_weights(hidden_prev_weights,n_hidden,n_out );
  492. //开始进行BP网络训练
  493. //这里设定最大的迭代次数为15000次
  494. for(l=0;l<15000;l++)  
  495. //对均方误差置零
  496. ex=0;
  497. //对样本进行逐个的扫描
  498. for(k=0;k<num;k++)  
  499. //将提取的样本的特征向量输送到输入层上
  500. for(i=1;i<=n_in;i++)
  501. input_unites[i] = data_in[k][i-1];
  502. //将预定的理想输出输送到BP网络的理想输出单元
  503. for(i=1;i<=n_out;i++)
  504. target[i]=data_out[k][i-1];
  505. //前向传输激活
  506. //将数据由输入层传到隐层 
  507. bpnn_layerforward(input_unites,hidden_unites,
  508. input_weights, n_in,n_hidden);
  509. //将隐层的输出传到输出层
  510. bpnn_layerforward(hidden_unites, output_unites,
  511. hidden_weights,n_hidden,n_out);
  512. //误差计算
  513. //将输出层的输出与理想输出比较计算输出层每个结点上的误差
  514. bpnn_output_error(output_deltas,target,output_unites,n_out);
  515. //根据输出层结点上的误差计算隐层每个节点上的误差
  516. bpnn_hidden_error(hidden_deltas,n_hidden, output_deltas, n_out,hidden_weights, hidden_unites);
  517. //权值调整
  518. //根据输出层每个节点上的误差来调整隐层与输出层之间的权值    
  519. bpnn_adjust_weights(output_deltas,n_out, hidden_unites,n_hidden,
  520. hidden_weights, hidden_prev_weights, eta, momentum); 
  521. //根据隐层每个节点上的误差来调整隐层与输入层之间的权值    
  522. bpnn_adjust_weights(hidden_deltas, n_hidden, input_unites, n_in,
  523. input_weights, input_prev_weights, eta, momentum);  
  524. //误差统计
  525. for(i=1;i<=n_out;i++)
  526. ex+=(output_unites[i]-data_out[k][i-1])*(output_unites[i]-data_out[k][i-1]);
  527. }
  528. //计算均方误差
  529. ex=ex/double(num*n_out);
  530. //如果均方误差已经足够的小,跳出循环,训练完毕  
  531. if(ex<min_ex)break;
  532. }
  533. //相关保存
  534. //保存输入层与隐层之间的权值
  535. w_weight(input_weights,n_in,n_hidden,"win.dat");
  536. //保存隐层与输出层之间的权值
  537. w_weight(hidden_weights,n_hidden,n_out,"whi.dat");
  538. //保存各层结点的个数
  539. w_num(n_in,n_hidden,n_out,"num");
  540. //显示训练结果
  541. CString str;
  542. if(ex<=min_ex)
  543. {
  544. str.Format ("迭代%d次,n平均误差%.4f",l,ex);
  545. ::MessageBox(NULL,str,"训练结果",NULL);
  546. }
  547. if(ex>min_ex)
  548. {
  549. str.Format("迭代%d次,平均误差%.4fn我已经尽了最大努力了还是达不到您的要求n请调整参数重新训练吧!",l,ex);
  550. ::MessageBox(NULL,str,"训练结果",NULL);
  551. }
  552. //释放内存空间
  553. free(input_unites);
  554. free(hidden_unites);
  555. free(output_unites);
  556. free(hidden_deltas);
  557. free(output_deltas);
  558. free(target);
  559. free(input_weights);
  560. free(hidden_weights);
  561. free(input_prev_weights);
  562. free(hidden_prev_weights);
  563. }
  564. /*******************************************
  565. * 函数名称
  566. * CodeRecognize()
  567. * 参量
  568. *  double **data_in     -指向待识别样本特征向量的指针
  569. *  int num              -待识别的样本的个数 
  570. *  int n_in             -Bp网络输入层结点的个数              
  571. *  int n_hidden         -Bp网络隐层结点的个数
  572. *  int n_out            -Bp网络输出层结点的个数
  573. * 函数功能:  
  574. *    读入输入样本的特征相量并根据训练所得的权值 
  575. *    进行识别,将识别的结果写入result.txt 
  576. ****************************************/
  577. void CodeRecognize(double **data_in, int num ,int n_in,int n_hidden,int n_out)
  578. {
  579. //循环变量
  580. int i,k;
  581. // 指向识别结果的指针 
  582. int *recognize;
  583. //为存放识别的结果申请存储空间
  584. recognize=(int*)malloc(num*sizeof(int));
  585. //指向输入层数据的指针
  586. double* input_unites; 
  587. //指向隐层数据的指针
  588. double* hidden_unites;
  589. //指向输出层数据的指针
  590. double* output_unites; 
  591. //指向输入层于隐层之间权值的指针
  592. double** input_weights;
  593. //指向隐层与输出层之间的权值的指针
  594. double** hidden_weights;
  595. //为各个数据结构申请内存空间
  596. input_unites= alloc_1d_dbl(n_in + 1);
  597. hidden_unites=alloc_1d_dbl(n_hidden + 1);
  598. output_unites=alloc_1d_dbl(n_out + 1);
  599. input_weights=alloc_2d_dbl(n_in + 1, n_hidden + 1);
  600. hidden_weights = alloc_2d_dbl(n_hidden + 1, n_out + 1);
  601. //读取权值
  602. if( r_weight(input_weights,n_in,n_hidden,"win.dat")==false)
  603. return;
  604. if(r_weight(hidden_weights,n_hidden,n_out,"whi.dat")==false)
  605. return;
  606. //逐个样本扫描
  607. for(k=0;k<num;k++)
  608. //将提取的样本的特征向量输送到输入层上
  609. for(i=1;i<=n_in;i++)
  610. input_unites[i]=data_in[k][i-1];
  611. //前向输入激活
  612.         bpnn_layerforward(input_unites,hidden_unites,
  613. input_weights, n_in,n_hidden);
  614.         bpnn_layerforward(hidden_unites, output_unites,
  615. hidden_weights,n_hidden,n_out);
  616. //根据输出结果进行识别
  617. int result=0 ;
  618. //考察每一位的输出
  619. for(i=1;i<=n_out;i++)
  620. {
  621. //如果大于0.5判为1
  622. if(output_unites[i]>0.5)
  623. result+=(int)pow(2,double(4-i));
  624. }
  625. //如果判定的结果小于等于9,认为合理
  626. if(result<=9)
  627. recognize[k]=result;
  628. //如果判定的结果大于9,认为不合理将结果定位为一个特殊值20
  629. if(result>9)
  630. recognize[k]=20;
  631. }
  632. //将识别结果写到文本中
  633. FILE *fp;
  634. fp=fopen("result.txt","w+");
  635. for(i=0;i<num;i++)
  636. {  
  637. if(recognize[i]==20)
  638. fprintf(fp,"无法识别,");
  639. else
  640. fprintf(fp,"%d,",recognize[i]);
  641. }
  642. fclose(fp);
  643. //将识别的结果显示出来
  644. CString str,str1;
  645. for(i=0;i<num;i++)
  646. {
  647. if(recognize[i]!=20)
  648. str.Format("%d ",recognize[i]);
  649. if(recognize[i]==20)
  650. str.Format("无法识别 ");
  651. str1+=str;
  652. }
  653. //通知用户训练完成
  654. ::MessageBox(NULL,str1,"识别结果",NULL);
  655. //释放存储空间
  656. free(input_unites);
  657. free(hidden_unites);
  658. free(output_unites);
  659. free(input_weights);
  660. free(hidden_weights);
  661. }