这是一个用于训练BP神经网络完成数字识别任务的小程序,较为简单,可以在此基础上进行修改,完成常见的分类任务。

这个东西该怎么使用?

首先,有一点需要明确的是,这是一个训练神经网络的工具,当然,也可以实现识别,但是由于当时只是想在PC上训练一个BP神经网络,然后移植到单片机上,求出BP网络的权重文件才是该软件的目的所在,所以,就没在GUI上添加具体的识别操作的按钮。如果需要,可以参考test方法自己实现一下。

整个程序可以在这里下载到:C#实现BP神经网络数字图像识别源码,也可以在github上下载:BPNetwork。

解压后会得到下面的目录,下面分别介绍一下:

  1. 测试样本:测试集,20*20的灰度图像,包含0~9;
  2. 训练样本:训练集,20*20的灰度图像,包含0~9;
  3. 训练成功后的矩阵:最终我个人训练的BP网络的权重矩阵;
  4. BPNetwork.exe:可执行程序;
  5. BPNetwork.rar:整个项目源码

具体原理:

  1. 将训练集和测试集中每一个20*20的图像拉伸为一个长度为400的数组;
  2. 利用train方法训练得到权重文件;
  3. 利用test方法测试所得到的BP神经网络的识别准确率。
using System;
using System.IO;
using System.Text;namespace BPNetwork
{/// <summary>  /// BpNet 的摘要说明。  /// </summary>  public class BpNet{/// <summary>/// 输入节点数/// </summary>public int inNum;  /// <summary>/// 隐层节点数/// </summary>int hideNum;  /// <summary>/// 输出层节点数  /// </summary>public int outNum;/// <summary>/// 样本总数/// </summary>public int sampleNum;  Random R;/// <summary>/// 输入节点的输入(输出)数据  /// </summary>double[] x;/// <summary>/// 隐层节点的输出  /// </summary>double[] x1;/// <summary>/// 输出节点的输出  /// </summary>double[] x2;/// <summary>/// 隐层的输入  /// </summary>double[] o1;/// <summary>/// 输出层的输入  /// </summary>double[] o2;/// <summary>/// 权值矩阵w  /// </summary>public double[,] w;/// <summary>/// 权值矩阵V  /// </summary>public double[,] v;/// <summary>/// 权值矩阵w  /// </summary>public double[,] dw;/// <summary>/// 权值矩阵V  /// </summary>public double[,] dv;/// <summary>/// 隐层阈值矩阵  /// </summary>public double[] b1;/// <summary>/// 输出层阈值矩阵  /// </summary>public double[] b2;/// <summary>/// 隐层阈值矩阵  /// </summary>public double[] db1;/// <summary>/// 输出层阈值矩阵/// </summary>public double[] db2;/// <summary>/// 隐层的误差/// </summary>double[] pp;/// <summary>/// 输出层的误差/// </summary>double[] qq;/// <summary>/// 输出层的教师数据/// </summary>double[] yd;/// <summary>/// 均方误差/// </summary>public double e;/// <summary>/// 归一化比例系数/// </summary>double in_rate;/// <summary>/// 计算隐藏层节点数/// </summary>/// <param name="m">输入层节点数</param>/// <param name="n">输出层节点数</param>/// <returns></returns>public int computeHideNum(int m, int n){double s = Math.Sqrt(0.43 * m * n + 0.12 * n * n + 2.54 * m + 0.77 * n + 0.35) + 0.51;int ss = Convert.ToInt32(s);return ((s - (double)ss) > 0.5) ? ss + 1 : ss;}/// <summary>/// 初始化神经网络/// </summary>/// <param name="innum">输入节点数</param>/// <param name="outnum">输出节点数</param>public BpNet(int innum, int outnum){// 构造函数逻辑  R = new Random();this.inNum = innum; //数组第二维大小 为 输入节点数  this.outNum = outnum; //输出节点数  this.hideNum = computeHideNum(inNum, outNum); //隐藏节点数x = new double[inNum];x1 = new double[hideNum];x2 = new double[outNum];o1 = new double[hideNum];o2 = new double[outNum];w = new double[inNum, hideNum];v = new double[hideNum, outNum];dw = new double[inNum, hideNum];dv = new double[hideNum, outNum];b1 = new double[hideNum];b2 = new double[outNum];db1 = new double[hideNum];db2 = new double[outNum];pp = new double[hideNum];qq = new double[outNum];yd = new double[outNum];//初始化w  for (int i = 0; i < inNum; i++){for (int j = 0; j < hideNum; j++){w[i, j] = (R.NextDouble() * 2 - 1.0) / 2;}}//初始化v  for (int i = 0; i < hideNum; i++){for (int j = 0; j < outNum; j++){v[i, j] = (R.NextDouble() * 2 - 1.0) / 2;}}e = 0.0;in_rate = 1.0;}/// <summary>/// 训练函数/// </summary>/// <param name="p">训练样本集合</param>/// <param name="t">训练样本结果集合</param>/// <param name="rate">学习率</param>public void train(double[,] p, double[,] t, double rate){//获取样本数量this.sampleNum = p.GetLength(0);e = 0.0;//求p,t中的最大值  double pMax = 0.0;for (int isamp = 0; isamp < sampleNum; isamp++){for (int i = 0; i < inNum; i++){if (Math.Abs(p[isamp, i]) > pMax){pMax = Math.Abs(p[isamp, i]);}}for (int j = 0; j < outNum; j++){if (Math.Abs(t[isamp, j]) > pMax){pMax = Math.Abs(t[isamp, j]);}}in_rate = pMax;}for (int isamp = 0; isamp < sampleNum; isamp++){//数据归一化  for (int i = 0; i < inNum; i++){x[i] = p[isamp, i] / in_rate;}for (int i = 0; i < outNum; i++){yd[i] = t[isamp, i] / in_rate;}//计算隐层的输入和输出  for (int j = 0; j < hideNum; j++){o1[j] = 0.0;for (int i = 0; i < inNum; i++){o1[j] += w[i, j] * x[i];}x1[j] = 1.0 / (1.0 + Math.Exp(-o1[j] - b1[j]));}//计算输出层的输入和输出  for (int k = 0; k < outNum; k++){o2[k] = 0.0;for (int j = 0; j < hideNum; j++){o2[k] += v[j, k] * x1[j];}x2[k] = 1.0 / (1.0 + Math.Exp(-o2[k] - b2[k]));}//计算输出层误差和均方差  for (int k = 0; k < outNum; k++){qq[k] = (yd[k] - x2[k]) * x2[k] * (1.0 - x2[k]);e += (yd[k] - x2[k]) * (yd[k] - x2[k]);//更新V  for (int j = 0; j < hideNum; j++){v[j, k] += rate * qq[k] * x1[j];}}//计算隐层误差  for (int j = 0; j < hideNum; j++){pp[j] = 0.0;for (int k = 0; k < outNum; k++){pp[j] += qq[k] * v[j, k];}pp[j] = pp[j] * x1[j] * (1 - x1[j]);//更新W  for (int i = 0; i < inNum; i++){w[i, j] += rate * pp[j] * x[i];}}//更新b2  for (int k = 0; k < outNum; k++){b2[k] += rate * qq[k];}//更新b1  for (int j = 0; j < hideNum; j++){b1[j] += rate * pp[j];}}e = Math.Sqrt(e);//adjustWV(w,dw);  //adjustWV(v,dv);  }/// <summary>/// 测试函数(单个数据测试)/// </summary>/// <param name="p">待测试样本</param>/// <returns>识别结果</returns>public int test(double[] p){double[,] w = new double[inNum, hideNum];double[,] v = new double[hideNum, outNum];double[] b1 = new double[hideNum];double[] b2 = new double[outNum];//1.读取权值矩阵系数readMatrixW(w, "w.txt");readMatrixW(v, "v.txt");readMatrixB(b1, "b1.txt");readMatrixB(b2, "b2.txt");//2.数据归一化  double pMax = 0.0;for (int i = 0; i < inNum; i++){if (Math.Abs(p[i]) > pMax){pMax = Math.Abs(p[i]);}}in_rate = pMax;//归一化系数for (int i = 0; i < inNum; i++){x[i] = p[i] / in_rate;}//3.计算隐层的输入和输出  for (int j = 0; j < hideNum; j++){o1[j] = 0.0;for (int i = 0; i < inNum; i++){o1[j] += w[i, j] * x[i];}x1[j] = 1.0 / (1.0 + Math.Exp(-o1[j] - b1[j]));}//4.计算输出层的输入和输出  for (int k = 0; k < outNum; k++){o2[k] = 0.0;for (int j = 0; j < hideNum; j++){o2[k] += v[j, k] * x1[j];}x2[k] = 1.0 / (1.0 + Math.Exp(-o2[k] - b2[k]));}//5.判断是否正确double max = x2[0];int maxi = 0;for(int i = 0; i < outNum; i++){if(x2[i] > max){max = x2[i];maxi = i;}}return maxi;}public void adjustWV(double[,] w, double[,] dw){for (int i = 0; i < w.GetLength(0); i++){for (int j = 0; j < w.GetLength(1); j++){w[i, j] += dw[i, j];}}}public void adjustWV(double[] w, double[] dw){for (int i = 0; i < w.Length; i++){w[i] += dw[i];}}/// <summary>/// 保存矩阵w,v  /// </summary>/// <param name="w">要保存的矩阵</param>/// <param name="filename">文件名</param>public void saveMatrix(double[,] w, string filename){StreamWriter sw = File.CreateText(filename);for (int i = 0; i < w.GetLength(1); i++){for (int j = 0; j < w.GetLength(0); j++){sw.Write(w[j, i].ToString("0.000000000000000") + " ");}sw.WriteLine();}sw.Close();}/// <summary>/// 保存矩阵b1,b2  /// </summary>/// <param name="b">要保存的阀值矩阵</param>/// <param name="filename">文件名</param>public void saveMatrix(double[] b, string filename){StreamWriter sw = File.CreateText(filename);for (int i = 0; i < b.Length; i++){sw.Write(b[i] + " ");}sw.Close();}/// <summary>/// 读取矩阵W,V  /// </summary>/// <param name="w">要读取到的那个矩阵</param>/// <param name="filename">文件所在位置</param>public void readMatrixW(double[,] w, string filename){StreamReader sr;try{sr = new StreamReader(filename, Encoding.GetEncoding("gb2312"));String line;int i = 0;while ((line = sr.ReadLine()) != null){string[] s1 = line.Trim().Split(' ');for (int j = 0; j < s1.Length; j++){w[j, i] = Convert.ToDouble(s1[j]);}i++;}sr.Close();}catch (Exception e){Console.WriteLine("The file could not be read:");Console.WriteLine(e.Message);}}/// <summary>/// 读取矩阵b1,b2  /// </summary>/// <param name="b">要读取的阀值矩阵</param>/// <param name="filename">文件所在位置</param>public void readMatrixB(double[] b, string filename){StreamReader sr;try{sr = new StreamReader(filename, Encoding.GetEncoding("gb2312"));String line;if ((line = sr.ReadLine()) != null){string[] strs = line.Trim().Split(' ');for (int i = 0; i < strs.Length; i++){b[i] = Convert.ToDouble(strs[i]);}}sr.Close();}catch (Exception e){Console.WriteLine("The file could not be read:");Console.WriteLine(e.Message);}}}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace BPNetwork
{public partial class MainFrm : Form{public MainFrm(){InitializeComponent();this.btnTest.Enabled = false;this.btnTrain.Enabled = false;this.txtLearnRate.Text = 0.3.ToString();//窗口固定大小this.MaximizeBox = false;//最大化按钮隐藏this.MinimizeBox = false;//最小化按钮隐藏this.FormBorderStyle = FormBorderStyle.FixedSingle;//不支持鼠标拖动this.lblMessage.Text = "请先载入测试或训练样本";}/// <summary>/// 训练按钮是否已经点击过一次/// </summary>private static int flag = 0;/// <summary>/// 训练文件是否已打开/// </summary>private static int flag2 = 0;/// <summary>/// 测试文件是否已打开/// </summary>private static int flag3 = 0;private BackgroundWorker bw;private void btnTrain_Click(object sender, EventArgs e){if (flag2 != 0)//测试文件和训练文件都已经选中{if (flag == 0){bw = new BackgroundWorker();bw.DoWork += Bw_DoWork;bw.RunWorkerCompleted += Bw_RunWorkerCompleted;bw.WorkerSupportsCancellation = true;//1.支持取消操作bw.RunWorkerAsync();this.btnTrain.Text = "停止";flag = 1;}else{this.btnTrain.Text = "训练";bw.CancelAsync();flag = 0;}}else{MessageBox.Show("请点击文件,选择要训练文件所在的目录!", "文件未载入");flag2 = 0;}}private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){this.Show();//隐藏窗体MessageBox.Show("训练成功", "提示");this.btnTrain.Text = "训练";flag = 0;}/// <summary>/// 训练样本的目录/// </summary>private static string train_path;/// <summary>/// 测试样本的目录/// </summary>private static string test_path;private void Bw_DoWork(object sender, DoWorkEventArgs e){//定义BP神经网络类BpNet bp = new BpNet(400, 10);double[] tmp = new double[20];try{//学习率double lr = Double.Parse(this.txtLearnRate.Text.Trim());int count = 0;//计数器int study = 0;//学习(训练)次数//数据字典Dictionary<string, int> filedictionary = new Dictionary<string, int>();for (int i = 0; i < 10; i++){string dir = train_path + @"\" + i + @"\";string[] files = Directory.GetFiles(dir);foreach (string item in files){filedictionary.Add(item, i);}}//声明数据存储区域double[,] input = new double[filedictionary.Count, 400];double[,] output = new double[filedictionary.Count, 10];//数据装载foreach (KeyValuePair<string, int> item in filedictionary){Bitmap bmp = new Bitmap(item.Key);for (int k = 0; k < bmp.Height; k++){for (int l = 0; l < bmp.Width; l++){input[count, k * bmp.Width + l] = bmp.GetPixel(l, k).R;}}//交换行,因为位图存储时,先存储最后一行,从图片的底部开始,逐渐向上扫描for (int k = 0; k < bmp.Height / 2; k++){for (int l = 0; l < bmp.Width; l++){tmp[l] = input[count, k * bmp.Width + l];input[count, k * bmp.Width + l] = input[count, (bmp.Height - 1 - k) * bmp.Width + l];input[count, (bmp.Height - 1 - k) * bmp.Width + l] = tmp[l];}}output[count, item.Value] = 1;//第j个图片被分为第i类count++;}do{if (!bw.CancellationPending)//2.检测用户是否取消{//训练bp.train(input, output, lr);study++;this.lblMessage.Text = "第" + study + "次训练的误差: " + bp.e;}else{break;//停止训练}} while (bp.e > 0.01 && study < 50000);}catch (Exception ex){MessageBox.Show("出错了" + ex.Message);}finally//出错或者中途取消也会保存权值矩阵的信息{bp.saveMatrix(bp.w, "w.txt");bp.saveMatrix(bp.v, "v.txt");bp.saveMatrix(bp.b1, "b1.txt");bp.saveMatrix(bp.b2, "b2.txt");this.lblMessage.Text = "训练终止!";}}private void btnTest_Click(object sender, EventArgs e){if (flag3 != 0 && File.Exists("w.txt") && File.Exists("v.txt") && File.Exists("b1.txt") && File.Exists("b2.txt")){//清空已有训练结果this.lbTestResult.Items.Clear();BackgroundWorker bw1 = new BackgroundWorker();bw1.DoWork += Bw1_DoWork;bw1.RunWorkerAsync();flag3 = 1;}else{MessageBox.Show("请点击文件,选择要测试文件所在的目录!", "文件未载入");flag3 = 0;}}private void Bw1_DoWork(object sender, DoWorkEventArgs e){try{//定义BP神经网络类BpNet bp = new BpNet(400, 10);int right_count = 0;string[] files;double[] tmp = new double[20];//读取文件for (int i = 0; i < 10; i++){right_count = 0;string dir = test_path + @"\" + i + @"\";files = Directory.GetFiles(dir);//共files.Length个样本,每个样本数据有400个字节double[] input = new double[400];double[] output = new double[10];for (int j = 0; j < files.Length; j++){Bitmap bmp = new Bitmap(files[j]);for (int k = 0; k < bmp.Height; k++){for (int l = 0; l < bmp.Width; l++){input[k * bmp.Width + l] = bmp.GetPixel(l, k).R;}}//交换行,因为位图存储时,先存储最后一行,从图片的底部开始,逐渐向上扫描for (int k = 0; k < bmp.Height / 2; k++){for (int l = 0; l < bmp.Width; l++){tmp[l] = input[k * bmp.Width + l];input[k * bmp.Width + l] = input[(bmp.Height - 1 - k) * bmp.Width + l];input[(bmp.Height - 1 - k) * bmp.Width + l] = tmp[l];}}if (i == bp.test(input)){right_count++;}}this.lbTestResult.Items.Add(files.Length + "个" + i + "样本识别成功率:" + (1.0 * right_count / files.Length * 100).ToString("0.00") + "%");}this.lblMessage.Text = "测试成功!";}catch (Exception ex){MessageBox.Show("出错了" + ex.Message);}}private void menuOpenTrain_Click(object sender, EventArgs e){FolderBrowserDialog path = new FolderBrowserDialog();path.ShowDialog();train_path = path.SelectedPath;flag2 = 1;this.btnTrain.Enabled = true;this.lblMessage.Text = "训练样本载入成功";}private void menuOpenTest_Click(object sender, EventArgs e){FolderBrowserDialog path = new FolderBrowserDialog();path.ShowDialog();test_path = path.SelectedPath;flag3 = 1;this.btnTest.Enabled = true;this.lblMessage.Text = "测试样本载入成功";}private static int flag1 = 0;private void menuStay_Click(object sender, EventArgs e){if (flag1 == 0){//窗口置顶this.TopMost = true;this.menuStay.Text = "取消窗口保持在前";flag1 = 1;}else{//取消窗口置顶this.TopMost = false;this.menuStay.Text = "窗口保持在前";flag1 = 0;}}private void menuRunBackground_Click(object sender, EventArgs e){this.Hide();//隐藏窗体}}
}

【C#】数字图像识别相关推荐

  1. 手写识别python_Python徒手实现识别手写数字—图像识别算法(K最近邻)

    Python徒手实现识别手写数字-图像识别算法(K最近邻) 写在前面 这一段的内容可以说是最难的一部分之一了,因为是识别图像,所以涉及到的算法会相比之前的来说比较困难,所以我尽量会讲得清楚一点. 而且 ...

  2. 数字图像识别笔记(第三章-灰度变换与空间滤波)

    title: 数字图像识别笔记(第三章-灰度变换与空间滤波(1)) categories: 数字图像识别 tags: 数字图像识别 date: 2020/10/1 20:33 mathjax: tru ...

  3. 数字图像识别笔记(第一章绪论)

    title: 数字图像识别笔记(第一章绪论) categories: 数字图像识别 tags: 数字图像识别 date: 2020/9/29 23:59 mathjax: true toc: true ...

  4. 使用ImageMagick和Tesseract进行简单数字图像识别

    使用ImageMagick和Tesseract进行简单数字图像识别 由于直接使用 tesseract 进行识别,识别率很低, ImageMagick 安装.配置及使用:  平台:winXP  1. 安 ...

  5. keras的数字图像识别

    aistudio地址: https://aistudio.baidu.com/aistudio/projectdetail/1484526 keras的数字图像识别 一.加载数据 MNIST数据集预加 ...

  6. 手写体数字图像识别图像_手写识别调整笔画大小而不是图像

    手写体数字图像识别图像 A straightforward algorithm to dealing with handwritten symbol recognition problems in M ...

  7. matlab图形设计界面 文献翻译,毕业设计基于matlab的数字图像识别的设计与实现文献翻译V8.1(资料4)...

    <[毕业设计]基于matlab的数字图像识别的设计与实现文献翻译.doc>由会员分享,可免费在线阅读全文,更多与<毕业设计基于matlab的数字图像识别的设计与实现文献翻译(V8.1 ...

  8. 这不仅仅是另一个使用TensorFlow来做MNIST数字图像识别的教程

    编者注:想学习如何从零开始构建和训练你的第一个TensorFlow图,请查看Aaron Schumacher在线教程里的<你好,TensorFlow!>! 请耐心看完这篇博文.每一个人学习 ...

  9. 【华为技术】【使用MoXing实现手写数字图像识别应用】【TensorFlow】

    原贴文章:https://bbs.huaweicloud.com/forum/thread-8533-1-1.html 在测试中如果遇到什么问题,欢迎大家到原贴下提问回复. 本文介绍在华为云深度学习服 ...

最新文章

  1. Error:org.gradle.api.internal.tasks.DefaultTaskInputs$TaskInputUnionFileCollection cannot be cast to
  2. Qt导入CMakeLists.txt后无法调试
  3. 跟小静读CLR via C#(02)-基元类型、引用类型、值类型
  4. Building and running Node.js for Android
  5. 对学校的希望和寄语_家长对孩子的期望寄语精选
  6. poj 1703(种类并查集)
  7. mysql 插入数据时,出现\xF0\x5F\x6F\x70问题
  8. 嵌入式linux组件,嵌入式Linux系统的几大组件!
  9. 学会python爬虫能发财么_python如何赚钱? python爬虫如何进阶? python就业? 如何快速入门python?...
  10. hdu 6155 - Subsequence Count
  11. Metatable让我从心认知了Lua(相知篇)
  12. 蓝图出炉:大家将能够利用英伟达技术打造自己的自动驾驶车辆
  13. 做了三年Java,java参考文献近五年图书
  14. iOS 集成极光推送 (swift版)
  15. debugger配置
  16. 快来看,数据分析BI软件居然也能完成基金变迁大数据分析?
  17. 谁将泡泡玛特推上千亿市值神坛?
  18. excel 区间人数柱状图_绩效评价还要分区间比较,Excel图表如何呈现?
  19. 《MATLAB 神经网络43个案例分析》:第5章 基于BP_Adaboost的强分类器设计——公司财务预警建模
  20. VS code编辑器出现open a floder or workspace... (File -> Open Folder)错误

热门文章

  1. 24c02读程序C语言详解,24C02读写操作程序(C语言)
  2. 全球最昂贵的10大科技产品
  3. 服务器间通过ssh使用密钥对实现无密码登录
  4. linux 把进程调到前台,【如何将后台运行的程序转到前台来?】
  5. ERP、MES、APS在生产排程上的区别?
  6. 计算机发展初期 承载信息的媒体,多媒体习题与答案(1).doc
  7. 4只鸭子在同一个圆圈内游泳,问:4只鸭子出现在同一个半圆内的概率是多少?Python模拟
  8. left semi join 和 left join 区别
  9. iOS-图片轮播-SDCycleSCrollView的使用
  10. [学习笔记]省选(算法?数据结构?)·线性基