精华内容
下载资源
问答
  • 手写体数字识别系统

    2011-09-22 17:02:17
    手写体数字识别系统可以识别手写数字,并可训练样本库;程序源代码!!!
  • 本文论述并设计实现了一个脱机自由手写体数字识别系统。文中首先对待识别数字的预处理进行了介绍,包括二值化、平滑滤波、规范化、细化等图像处理方法;其次,探讨了如何提取数字字符的结构特征和笔划特征,并详细地...
  • 神经网络写的手写体数字识别系统的原码,可以看一下
  • 基于支持向量机的手写体数字识别系统设计论文
  • UI 设计包括界面设计、菜单栏布局、进度条、结果展示和图片展示区域划分 几个主要任务。图像预处理包括图像的灰度化、二值化、...字矩阵数组,采用不同的识别方法,一个个地识别出他们对应的数字,最终显示 在界面。
  • 手写体数字识别系统的MATLAB实现

    热门讨论 2011-06-27 12:13:33
    使用MATLAB实现的手写体数字识别系统
  • 手写体数字识别系统的源代码 对大家非常又帮助
  • 使用MATLAB自用工具包调用摄像头,进行图像处理、分割、保存,形成自制的训练集与测试集识别数字0与2,但是其他数字也可以,读者可自己进行操作验证;2.特征提取部分采用了粗网格特征提取,最大限度地降低了特征的...
  • 简单手写体数字识别系统

    千次阅读 2007-10-22 17:55:00
    简单手写体数字识别系统 作者:陈海艺 (广西工学院 计算机系)下载源代码摘要 为了实现对手写字体的识别,运用了人工智能的分层神经网络思想,对识别的字体通过训练学习,达到识别手写字体的功

                                                                  简单手写体数字识别系统

                                                  作者:陈海艺 (广西工学院 计算机系)下载源代码

    摘要
      为了实现对手写字体的识别,运用了人工智能的分层神经网络思想,对识别的字体通过训练学习,达到识别手写字体的功能。

    关键字 VC,人工智能,神经网络,手写识别。

    1 引言

    1.1 编写目的
      人工智能英文名表示是"Artificial Intelligence",简称 AI,也就是用计算机模拟人的思维和知识,通过对本系统的学习开发,对计算机人工智能和神经网络有了初步的认识,萌发初学者对人工智能和网络神经学习的基本方法和思路。

    1.2 背景
      目前市面上的语音识别系统和手写识别,指纹识别系统大都建立在人工智能的神经网络技术的基础上,神经网络技术是解决识别系统难题的适当方法。

    2 必备知识

    2.1 vc基础
      本系统采用vc开发,所以希望读者对vc也要熟悉。

    2.2神经网络
      下面我们来对神经网络技术有个大体的认识,
    这里说的神经网络,实质上是指人工神经网络,是模拟生物神经元的实现,神经网络又分单层神经网络(不带输入层),和多层神经网络,实验证明,神经网络的的层数多少不影响网络对实体的识别,可能有人会问,为什么还需要多层神经网络的开发呢?答案是,适当的多层结构可以使网络的训练学习进度提高,可以更快地收敛到需要的权值上,但层数越多,或者层数不多都不足以证明能够越快地收敛到需要的权值上,这里的研究不属于我们的范畴,我们这里采用的使分层前向神经网络,结构图如下(图1)



    3.算法

    3.1.算法思想

    • (1)界面方面:这里我们先来熟悉一下算法的思想,为了使程序跟用户有交流界面,我们必须提供一个给用户输入的终端,这里我们用鼠标代替手写,并绘制一个输入终端用于提取我们的输入,首先子类化一个静态控件,并给重绘重载,在里面绘制控件的背景(白色),和网格线(淡青色),通过矩阵的信息进行点的重绘,响应鼠标事件,用来绘制终端的点。
    • (2)神经网络:我们这里采用了10×10的网格结构,为了是算法清晰易见,所以输入采用100个输入,事实上用到的点没有那么多,用户可以根据需要更改,中间的隐层采用5个输入,因为我们只是识别数字,所以只是有10个输出就足够了,(其实不用10个输出也可以完成任务,1010就可以标识10了,可以只要四位,但是还是那句话,为了算法清晰易见),所以神经网络的结构是100:5:10.可以通过改变源代码的define来改变网络拓扑结构。

    3.2 算法描述

    (1)学习

    设输入层为n个输入,隐层是m个输入,输出层是p个输出

    1.初始化V,W,α,ε //给V,W赋初值,这里用随机值,有经验的话可以给V和W
    //赋一个近似的初值,这样的话可以加快收敛速度。
    // 是学习因子,可以根据学习的进度来动态改变,这里自始
    //至终取0.7, 是精度系数,

    2.循环学习直到误差小于精度

    e=(I,T) //对每一个样本取样放到集合e中 ,I代表输入样本,T代表输出样板

    求a[j]=g(in[j])=g(//求隐层的值,其中V是各个权值的向量,
                                        //I是样板值
    o[i]=g(in[i])=g(//求输出层的值,其中W是各个隐层输入的
                                      //权值,a[j]是输入的隐层的值

    Err[i]=T[i]-O[i] (1<=i<=p) //Err是误差值
    
    求 [i]=Err[i]*g`(in[i])      (1<=i<=p)               //g`(in[i])是g(in[i])函数的求导
    W[j,i]=W[j,i]+  *a[j]*Err[i]*g`(in[i])               //权值调整,即训练学习, 是学习因子,用
                                                         //来反映学习的频率,可以自己根据程序需要来定
    

      这里遇到一个难题是隐层的误差值怎么求,因为输出层有准确的输出值作参考,所以能够求到误差值,但是隐层没有相应的准确值。我们可以观察输出层的误差值,这个值其实蕴涵了隐层的误差值所在,经过证明可以用下面公式获取误差值。

    Err[j]= //Err(1<=j<=P)是输出层的误差,这里
    //利用这个误差蕴涵的信息来获取隐
    //层的误差
    
    V[k,j]=V[k,j]+ *I[k]*Err[j]*g`(in[j]) //隐层权值修正

    3.返回V,W,学习完成

      可能有些人不明白函数g(x)是如何选取,根据我们识别的特性来看,我们应该选择,S型函数(关于函数的类型请参阅其他书籍),考虑函数的导数在内,应该选择一个比较好导的函数。所以我们选择。

    y=f(A)=1/(1+Exp(-A))
    y`=f`(A)=y(1-y) 

    (2)实现识别

    1.获取输入层的各个值 a

    a[j]=g(in[j])=g( 把P改成m //求隐层的值,其中V是各个权值
                              //的向量,

    o[i]=g(in[i])=g( //求输出层的值,其中W是各个隐层输入的
     

    Err[i]=(T[i]-O[i])2 /2
    // 为精度,如果全局误差都小于精度就//证明输出的矩阵O是合法的。
    

    // ε为精度,如果全局误差都小于精度就//证明输出的矩阵O是合法的。

    3.3算法实现
      设输入层为n个输入,隐层是m个输入,输出层是p个输出。
    *这里是一次训练的算法,程序可以根据自己需要实现。

    INPUT W,V,P,A                //输入权值W,V,精度P,和学习系数A
    INPUT i[1],...,i[n],t[1],...,t[p]      //输入和输出样板集
    Step 1  Set v_sum=0.           //设定累加器
    Step 2  Set in_i[m],in_j[p]       
    
    Step 3  For j=1,...,m do Step 4 and Step 5,Step 7
    Step 4    Set  in_j[j]=0;        //初始化
    Step 5  For k=1,...,n do Step6 and Step7
    Step 6    Set in_j[j]=a[j]+(v[k,j]*i[k]);
    Step 7  Set a[j]=1/(1-Exp(-in_j[j]));
      
    Step 8 For i=1,...,p do Step9 and Step 10,Step 12
    Step 9  Set  in_i[i]=0;
    Step 10  For j=1,...,m do Step 11
    Step 11    Set in_i[i]=in_i[i]+(w[j,i]*a[j])
    Step 12  Set o[i]=1/(1-Exp(-in_i[i]);
    
    Step 13 For i=1,...,p do Step 14
    Step 14  Set Err[i]=t[i]-o[i]     //误差
    
    Step 15 For j=1,...,m do Step 16
    Step 16  For i=1,...,p do Step 17
    Step 17    Set w[j,i]=w[j,i]+A*a[j]*Err[i]* 1/(1-Exp(-in_j[j]))(1-1/(1-Exp(-in_j[j])));//输出层权
    //值修正
    
    Step 18 For k=1,...,n do Step 19
    Step 19  For j=1,...,m do Step 20
    Step 20    Set v[k,j]=v[k,j]*A*i[k]*Err[j]* 1/(1-Exp(-in_j[j]))(1-1/(1-Exp(-in_j[j])));//隐层权值
    //修正
    
    Step 21 OUTPUT (Err[1],...,Err[p])
    STOP      

    重复训练过程来对准确权值的收敛,识别过程是学习过程的一部分,所以这里不再重复

    3.4 终端处理位置居中
      要使识别系统能够处理同一个输入终端但是有坐标偏移的问题,要作一些坐标转换,就是先获取中点坐标,然后根据中点坐标的偏移来平移,注意,这里的平移,包括样本,和输入层的点都要作平移。具体实现请参见附件的源代码

    4.实现效果

    采样效果



    训练后的识别效果



    5.总结
      通过对手写数字识别系统的开发,熟悉了人工神经网络的基本工作方式,神经网络有很多种,每一种都有自己的特点和功能,人工神经网络还可以拓展到其他领域,我国的人工智能研究起步比较迟,还需要很大的努力才能跟上其他发达国家的水平。

    展开全文
  • 图像预处理包括图像的灰度化、二值化、反色处理、图形锐化、 数字分割、归一化等主要任务。特征提取为使用不同的特征提取方法,对于预处 理过的图像,进行数字特征提取
  • BP神经网络自由手写体数字识别系统

    千次阅读 2017-12-22 18:02:44
    手写体识别问题可以追溯到20世纪20年代,当时提出了统计方法可能是最佳的选择,手写体识别在生活中会有很多的地方应用,例如:邮局里信件堆积如山,因此需要借助自动化手段识别邮政编码,实现自动化和高效地分拣...

    手写体识别问题可以追溯到20世纪20年代,当时提出了统计方法可能是最佳的选择,手写体的识别在生活中会有很多的地方应用,例如:邮局里信件堆积如山,因此需要借助自动化手段识别邮政编码,实现自动化和高效地分拣邮件。

    实现手写体识别也有其他的方法,比如使用OCR(光学字符识别),通过将手写文档读入,然后识别文字后生成电子文档,但是这种识别的效率不高,但是如果将OCR结合着大数据和机器学习肯定会将准确率达到一个新的高度,本篇文章只是基于BP神经网络实现了一个简单的手写数字识别系统,性能也不是很好,但是这是一个起点,从这里出发可以做出很多有趣的事物,比如商品识别、语言翻译、游戏AI、图片还原等等。


    简介

    首先说明几个概念,首先机器学习就是通过大量数据训练一个能够识别多种模式的系统。训练系统用的数据集合称为训练集,如果训练集的每个数据条目都打上目标输出数据(标签),则该方法称作监督学习,不打标签的就是非监督学习。机器学习中有多种算法都是能够实现手写字符识别的,本文中就是基于神经网络实现该系统。

    神经网络:由能够相互通信的节点构成,赫布理论解释了人体的伸进网络是如何通过改变自身的结构和神经连接的强度来记忆某种模式的。而人工智能终端神经网络与此类似。

    在下面的图中,最左边一列蓝色节点是输入节点,最右列节点是输出节点,中间是隐藏节点。该结构是分层的,隐藏的部分有时候也会分为多个隐藏层,如果使用的层数非常的多就是平常说的深度学习。

    这里写图片描述

    其中每一层(除了输入层)的节点由前一层的节点加权相加加偏置向量并经过激活函数得到,公式如下:
    这里写图片描述

    其中f是激活函数,b是偏置向量

    这一类拓扑结构的神经网络称作前馈神经网络,因为该结构中不存在回路。有输出反馈给输入的神经网络称作递归神经网络(RNN)。在本课程中我们使用前馈神经网络中经典的BP神经网络来实现手写识别系统。

    神经网络属于监督学习,那么就三件事情,决定模型参数,通过数据集训练学习,训练好后就能到分类工具/识别系统用了。
    数据集可以分为三部分:训练集、验证集、测试集。训练集是系统通过对比正确答案和自己的解答不断学习改良自己。测试集可以看做是一次性的比对,没有正确答案。验证集就是多个测试中选择最好的,验证集决定模型参数。


    系统构成

    OCR系统分为五个部分:

    • 客户端(ocr.js)
    • 服务器(server.py)
    • 用户接口(ocr.html)
    • 神经网络(ocr.py)
    • 神经网络设计脚本(neural_network_design.py)

    目录结构:

    这里写图片描述

    用户接口(ocr.html)是一个html页面,用户在画板上写数字,之后点击选择训练或是预测。

    客户端(ocr.js)将收集到的手写数字组合成一个数组发送给服务器端(server.py)处理,服务器调用神经网络模块(ocr.py),它会在初始化时通过已有的数据集训(data.csv、dataLabels.csv)练一个神经网络,神经网络的信息会被保存在nn.json中,等之后再一次启动时使用。

    最后,神经网络设计脚本(neural_network_design.py)是用来测试不同隐藏节点数下的性能,决定隐藏节点数用的。


    下面的完整的代码我已上传到GitHub中:https://github.com/HinWill/Identify


    用户接口(ocr.html ocr.js)

    需要给予用户输入数据、预测、训练的接口。在 ocr.html 中.


    手写输入等主要的客户端逻辑主要在ocr.js中实现

    画布的设定为20*20:

    var ocrDemo = {
        CANVAS_WIDTH: 200,
        TRANSLATED_WIDTH: 20,
        PIXEL_WIDTH: 10, // TRANSLATED_WIDTH = CANVAS_WIDTH / PIXEL_WIDTH

    在画布上加入网格辅助输入和查看:

        drawGrid: function(ctx) {
            for (var x = this.PIXEL_WIDTH, y = this.PIXEL_WIDTH; 
                     x < this.CANVAS_WIDTH; x += this.PIXEL_WIDTH, 
                     y += this.PIXEL_WIDTH) {
                ctx.strokeStyle = this.BLUE;
                ctx.beginPath();
                ctx.moveTo(x, 0);
                ctx.lineTo(x, this.CANVAS_WIDTH);
                ctx.stroke();
    
                ctx.beginPath();
                ctx.moveTo(0, y);
                ctx.lineTo(this.CANVAS_WIDTH, y);
                ctx.stroke();
            }
        },

    使用一维数组来存储手写输入,也可以使用二维数组,更加直观。
    0代表黑色(背景色),1代表白色(笔刷色),手写输入与存储的代码:

      onMouseMove: function(e, ctx, canvas) {
            if (!canvas.isDrawing) {
                return;
            }
            this.fillSquare(ctx, 
                e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop);
        },
    
        onMouseDown: function(e, ctx, canvas) {
            canvas.isDrawing = true;
            this.fillSquare(ctx, 
                e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop);
        },
    
        onMouseUp: function(e) {
            canvas.isDrawing = false;
        },
    
        fillSquare: function(ctx, x, y) {
            var xPixel = Math.floor(x / this.PIXEL_WIDTH);
            var yPixel = Math.floor(y / this.PIXEL_WIDTH);
            //在这里存储输入
            this.data[((xPixel - 1)  * this.TRANSLATED_WIDTH + yPixel) - 1] = 1;
    
            ctx.fillStyle = '#ffffff'; //白色
            ctx.fillRect(xPixel * this.PIXEL_WIDTH, yPixel * this.PIXEL_WIDTH, 
                this.PIXEL_WIDTH, this.PIXEL_WIDTH);
        },
    

    下面完成在客户端点击训练键时触发的函数。

    当客户端的训练数据到达一定数量时,就一次性传给服务器端给神经网络训练用:

       train: function() {
            var digitVal = document.getElementById("digit").value;
            // 如果没有输入标签或者没有手写输入就报错
            if (!digitVal || this.data.indexOf(1) < 0) {
                alert("Please type and draw a digit value in order to train the network");
                return;
            }
            // 将训练数据加到客户端训练集中
            this.trainArray.push({"y0": this.data, "label": parseInt(digitVal)});
            this.trainingRequestCount++;
    
            // 训练数据到达指定的量时就发送给服务器端
            if (this.trainingRequestCount == this.BATCH_SIZE) {
                alert("Sending training data to server...");
                var json = {
                    trainArray: this.trainArray,
                    train: true
                };
    
                this.sendData(json);
                // 清空客户端训练集
                this.trainingRequestCount = 0;
                this.trainArray = [];
            }
        },
    

    接着完成在客户端点击测试键(也就是预测)时触发的函数:

        test: function() {
            if (this.data.indexOf(1) < 0) {
                alert("Please draw a digit in order to test the network");
                return;
            }
            var json = {
                image: this.data,
                predict: true
            };
            this.sendData(json);
        },
    
    

    最后,我们需要处理在客户端接收到的响应,这里只需处理预测结果的响应:

        receiveResponse: function(xmlHttp) {
            if (xmlHttp.status != 200) {
                alert("Server returned status " + xmlHttp.status);
                return;
            }
            var responseJSON = JSON.parse(xmlHttp.responseText);
            if (xmlHttp.responseText && responseJSON.type == "test") {
                alert("The neural network predicts you wrote a \'" 
                       + responseJSON.result + '\'');
            }
        },
    
        onError: function(e) {
            alert("Error occurred while connecting to server: " + e.target.statusText);
        },
    
    

    最后整个客户端的效果如下:

    这里写图片描述


    服务器端(server.py)

    服务器端由Python标准库BaseHTTPServer 实现,我们接受从客户端发来的训练或是预测请求,使用POST报文,由于逻辑简单,这两种请求就发给一个URL


    实现神经网络(ocr.py)

    这里使用的方向传播算法来训练神经网络,算法背后的原理推导可以看这里的:反向传播神经网络入门

    这里简单的介绍下算法的三个步骤:


    第一步:初始化神经网络

    一般将所有权值和偏置量置为(-1,1)范围内的随机数,在这里,使用(-0.06,0.06)这个范围,输入层到隐藏层的权值存储在矩阵theta1中,偏置量存在input_layer_bias中,隐藏层到输出层则分别存在theta2与hidden_layer_bis中。

    创建随机阵的代码如下,这里输出的矩阵是以size_out为行,size_in为列。一般待处理的输入放在右边,处理操作(矩阵)放在左边,所以这里的size_in在左边

    def _rand_initialize_weights(self, size_in, size_out):
        return [((x * 0.12) - 0.06) for x in np.random.rand(size_out, size_in)]

    初始化权值矩阵和偏置向量:

    self.theta1 = self._rand_initialize_weights(400, num_hidden_nodes)
    self.theta2 = self._rand_initialize_weights(num_hidden_nodes, 10)
    self.input_layer_bias = self._rand_initialize_weights(1, 
                                                          num_hidden_nodes)
    self.hidden_layer_bias = self._rand_initialize_weights(1, 10)

    这里说明一下会用到的每一个矩阵/向量及其形状:

    y0                          输入                   1 * 400
    theta1                      输入-隐藏层权值矩阵      隐藏层节点数 * 400
    input_layer_bias            输入-隐藏层偏置向量      隐藏层节点数 * 1
    y1                          隐藏层                 隐藏层节点数 * 1
    theta2                      隐藏-输出层权值矩阵      10 * 隐藏层节点数
    hidden_layer_bias           隐藏-输出层偏置向量      10 * 1
    y2                          输出层                 10 * 1

    第二步:前向传播

    前向传播就是输入数据通过一层一层计算到达输出层得到输出结果,输出层会有10个节点分别代表0~9,哪一个节点的输出值最大就作为我们预测的结果,一般用sigmoid函数作为激发函数

    # sigmoid激发函数
    def _sigmoid_scalar(self, z):
        return 1 / (1 + math.e ** -z)

    这个函数长这个样子:

    这里写图片描述

    可以将实数范围的数字映射到(0,1),S型的形状很理想,因为导数可以直接得到。

    使用numpy和vectorize能得到标量函数的向量化版本,这里可以直接处理向量:

    self.sigmoid = np.vectorize(self._sigmoid_scalar)

    向前传播的代码:

    y1 = np.dot(np.mat(self.theta1), np.mat(data['y0']).T)
    sum1 =  y1 + np.mat(self.input_layer_bias)
    y1 = self.sigmoid(sum1)
    
    y2 = np.dot(np.array(self.theta2), y1)
    y2 = np.add(y2, self.hidden_layer_bias)
    y2 = self.sigmoid(y2)
    

    第三步:反向传播

    这一步是训练的关键,它需要通过计算误差率后,系统根据误差改变网络的权值矩阵和偏置向量。通过训练数据的标签我们得到actual_vals用来和输出层相减得到误差率output_errors,输出层的误差只能用来改进上一层,要想改进上上一层就需要计算上一层的输出误差

    actual_vals = [0] * 10 
    actual_vals[data['label']] = 1
    output_errors = np.mat(actual_vals).T - np.mat(y2)
    hidden_errors = np.multiply(np.dot(np.mat(self.theta2).T, output_errors), 
                                self.sigmoid_prime(sum1))
    

    其中sigmoid_prime的作用就是先sigmoid再求导数

    更新权重矩阵与偏置向量:

    self.theta1 += self.LEARNING_RATE * np.dot(np.mat(hidden_errors), 
                                               np.mat(data['y0']))
    self.theta2 += self.LEARNING_RATE * np.dot(np.mat(output_errors), 
                                               np.mat(y1).T)
    self.hidden_layer_bias += self.LEARNING_RATE * output_errors
    self.input_layer_bias += self.LEARNING_RATE * hidden_errors
    

    LEARNING_RATE是学习进步,这里设置为0.1是为了结果会更精准

    def predict(self, test):
        y1 = np.dot(np.mat(self.theta1), np.mat(test).T)
        y1 =  y1 + np.mat(self.input_layer_bias) # Add the bias
        y1 = self.sigmoid(y1)
    
        y2 = np.dot(np.array(self.theta2), y1)
        y2 = np.add(y2, self.hidden_layer_bias) # Add the bias
        y2 = self.sigmoid(y2)
    
        results = y2.T.tolist()[0]
        return results.index(max(results))

    实现神经网络设计脚本

    神经网络设计脚本的功能就是决定神经网络使用的隐藏节点的数量,这里从5个节点开始增长,每次增加5个,到50个为止,打印性能进行比较,其中数据集为data.csv 、dataLabels.csv这两个在我的GitHub上,可以下载到本地。
    运行脚本查看结果(注意每次初始化时的参数是随机的,训练顺序也是随机的,所以每个人的训练结果应该是不一样的):

    这里写图片描述

    通过输出我们判断15个隐藏节点可能是最优的。从10到15增加了1%的精确度,之后需要再增加20个节点才能有如此的增长,但同时也会大大地增加了计算量,因此15个节点性价比最高。当然不追求性价比电脑性能也够用的话还是选择准确度最高的节点数为好。


    实验结果:

    打开服务器 server.py 在ocr.html上写一个数字:

    这里写图片描述


    这个系统不仅可以分析数值或者是文本数据,还可以用来分析图像,甚至是由相机或者扫描仪生成的手写体图像


    参考资料&延伸阅读

    Optical Character Recognition (OCR)
    Optical Character Recognition (OCR) 源代码
    [反向传播神经网络极简入门](http://www.hankcs.com/ml/back-propagation-neural-network.html)
    Error Backpropagation

    展开全文
  • 单文档程序,使用位图和模拟按钮。识别率达80%,并且经过并接,可以算是合格的毕业论文,有需要的话可以参考下,鉴于本科毕业论文,我只能把分弄高点啊!
  • 摘要:通过对手写体数字识别技术的研究,本文建立了一个脱机手写体数字识别系统,对手写体数字的识别提出了一些新的思路,并对识别过程中所采用的关键算法进行了阐述。本文提出了二次毛刺去除法对手写体数字图像进行...

空空如也

空空如也

1 2 3 4 5 ... 10
收藏数 190
精华内容 76
关键字:

手写体数字识别系统