摘要
读者们好,本文希望以平实细致的语言,向读者描述以下内容:
1)经典开源程序OCR的详细介绍;
2)如何通过修改OCR源码,“随心所欲”地给其添加、修改功能;
修改源码的过程涉及到python,前端开发三大语言(html,css,JavaScript)。“东风吹雨过青山,却望千门草色闲”,有兴趣的同学不妨随我一起走进OCR探索之旅吧!
前言
在本章,我们会展示一个用ANN(人工神经网络)对手写数字进行识别的程序。
该程序有以下一些特性:
1)前端(网页)用JavaScript,html 5,css开发;
2)后端(服务器)用python写的(2.7版本);
3)功能:
- 支持在网页画布上(用鼠标)写数字,并会返回预测结果;
- 支持重置网页画布;
- 支持向服务器发送训练样本;
- 支持图片预览,图片上传;
- 支持对上传的图片中英文字母的识别。
这是一个非常酷的程序,C/S架构,代码也不是很复杂,而且设计了一些很有趣的知识(机器学习,神经网络,http数据传递,前后端开发等等)。感兴趣的同学可以从我的CSDN资源页下载下来看一看,有不懂的可以评论留言。
一、OCR为何物?
设想,你在网页上手写一个数字,然后网页立马给你返回识别结果,是不是很酷?这就是本文要研究的程序——OCR。
OCR,全称为Optical Character Recognition,即光学字符识别。这个程序是开源程序架构系列的第四本《500 Lines or Less》(注意:这本书尚未出版,但是已经公布在github上了)中的很有趣的一个C/S架构程序,简单来说,其功能为用人工神经网络识别0-9的手写数字。
下面对其进行具体介绍:
1.1 源程序下载地址
源程序已公布在github上,可以直接下载:https://github.com/aosabook/500lines/tree/master/ocr/code
同时,出版方给出了对OCR的英文简介 (源码及简介的作者:Marina Samuel,不用多说,应该是妥妥的大牛),地址为:http://aosabook.org/en/500L/optical-character-recognition-ocr.html
再者,还有好心人进行了中文翻译,地址为:Optical Character Recognition (OCR)。
1.2 OCR的功能展示
OCR是C/S架构(即client-server,作者就是这么说的),但我觉得准确来说是一个B/S架构,因为用户界面是直接展示在网页上的,如图(主界面):
5)Test按钮:这是一个测试按钮,你要先在画布上画一个数字,然后点击test,网页会弹出一个结果
1.3 OCR的程序结构
可以看到,OCR由
1)2个csv文件(包含训练样本和对应标签),
2)一个neural_network_design.py(用来训练人工神经网络,找到最合适的隐藏层节点数),
3)nn.json(存着人工神经网络的各个参数),
4)ocr.html(对网页界面进行设计),
5)ocr.js(发送http post请求给服务器,然后又接受服务器返回的结果;定义了train,test,reset按钮对应的函数,一旦你按下按钮,就会触发这些函数,从而实现相关功能),
6)ocr.py(用python自定义了一个类:OCRNeuralNetwork,即实现了一个Artificial Neural Network;定义了类方法train()和predict(),可以对样本进行训练,也可以对我们在网页上的手写数字进行预测(识别))
7)server.py(这个文件用来处理前端网页发送过来的http请求。具体的,它先实例化一个OCRNeuralNetwork,然后处理传送过来的json数据。)
下面简单(有选择性的)展示一下OCR的一些代码吧。
1.3.1 ocr.html
<html>
<head>
<script src="ocr.js"></script>
<link rel="stylesheet" type="text/css" href="ocr.css">
</head>
<body onload="ocrDemo.onLoadFunction()">
<div id="main-container" style="text-align: center;">
<h1>OCR Demo</h1>
<canvas id="canvas" width="200" height="200"></canvas>
<form name="input">
<p>Digit: <input id="digit" type="text"> </p>
<input type="button" value="Train" onclick="ocrDemo.train()">
<input type="button" value="Test" onclick="ocrDemo.test()">
<input type="button" value="Reset" onclick="ocrDemo.resetCanvas();"/>
</form>
</div>
</body>
</html>
诺,就这么点代码,可以说是很少了,所以ocr的界面看上去那么…粗糙。但是,学过html的同学可能知道,```这一行代码其实是引用了一个css布局文件的,可惜,作者似乎并没有在源码中给出(我感觉是作者并没有写,可能以后会填坑吧),所以最后的界面也没有进行任何布局。
1.3.2 ocr.js
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);
},
这一段代码定义了fillSquare函数,输入时停在画布上的鼠标指针,输出是给指针对应的画布格子填充和背景不同的颜色(多次调用这个函数就能够实现在画布上手写数字了)。**但是!**我发现这个函数有bug——即这一行代码this.data[((xPixel - 1) * this.TRANSLATED_WIDTH + yPixel) - 1] = 1;
,这一行是为了给data的下标从0到399赋值,但是,当xPixel=1,yPixel=0的时候,data的下标就变成了-1,又或者xPixel=0,yPixel=1(这些都是画布上实际可能出现的值,不是我编的),data下标又变成了-20。我认为这是一个bug,会导致手写数字的数据无法被正确表示出来。此处贴出我修改后的代码:
fillSquare: function(ctx, x, y) {
var xPixel = Math.floor(x / this.PIXEL_WIDTH);
var yPixel = Math.floor(y / this.PIXEL_WIDTH);
this.data[((xPixel) * this.TRANSLATED_WIDTH + yPixel) ] = 1;//修改代码处
ctx.fillStyle = '#ffffff';
ctx.fillRect(xPixel * this.PIXEL_WIDTH, yPixel * this.PIXEL_WIDTH, this.PIXEL_WIDTH, this.PIXEL_WIDTH);
},
其他的由于时间限制,且笔墨太多,各位看了可能还会厌烦,这里就不一一说明了。有感兴趣者可以下方评论与我探讨。
下面具体介绍我们的OCR修改之路。
二、OCR修改之路
2.1 修改功能——改OCR写字板(以及添加小logo)
这个的话,直接修改html就行。我是把css里面的内容也直接写在html里面了(没有另外新建一个css文档,这个不打紧,效果是一样的。)代码的话这里也不贴了,有点多,直接在我们的github上可以下载的。后面同理。
虽然说修改html看上去很容易,但是非常费时间,毕竟没有基础。下面直接展示修改过后的网页:
修改了很多地方。
1)采用了多个<div></div>
2)在head部分定义了一些style
3)增加了网页的名字和小logo(在网页的最上面可以看到)
4)增加了简介,结尾的联系方式(添加了一些必要的源代码,我们的联系方式等链接)
5)添加了一个比较酷的上传照片的按钮(upload)
6)修改了画布;
7)对整个网页的字体大小,类型,以及背景色,都做了一些讲究。
2.2 添加功能——丰富网页内容
如图2.1.1和图2.1.2所示,我们还是丰富了不少网页内容的,原先是孤零零的一个ocr画布,现在增加了更多的介绍,以及功能对应的网页界面,这些都是必要的(让网页变得更加美观,简单实用)。
2.3 添加功能——在网页上显示训练样本
我们添加了一个show one sample按钮,点击它,后端服务器就会从训练样本中随机选一个样本,然后展示到图片上。
这里需要修改html,server.py,ocr.py三个文件。
2.4 添加功能——对用户上传的图片(含英文文字)进行文字识别,并在网页上显示识别结果
这个功能实现要安装tesseract,还要安装pytesseract。总会比较麻烦,有想讨论的评论回复,当然,以后我有时间了,会详细补充的。
2.5 修改后的源代码下载地址(GitHub)
https://github.com/DehengYang/OCR_modified
但是我github上少了一个data.csv文件,因为太大了,当时没有传上去。
所以有需要的同志可以去我的CSDN资源页下载。
2.6 “平凡之路”
一开始真的是,都不知道程序入口在哪里。所以从0开始,读代码,看工具书(js,html,python,机器学习等等),不断调试,明白基本功能,原理之后,又开始想着修改,添加功能。于是又读代码,看工具书,调试……前后大概近2周时间(虽然不是一天到晚都在看,但是基本每天都有在学,在研究)吧。
为什么我觉得自己花了很多时间,因为这些对我来说都是新知识,以前从来没有接触过html,css,JavaScript(包括jQuery的一些知识)等等,以及对python有一些实践,但是不够深入。在这样的情况下,可以算是一步一个脚印的开始学习,修改了。
总而言之,我觉得此次OCR修改之路是艰辛但却意义非凡的。我本来就觉得自己的编程能力太弱,所以在此非常感谢老师给我们小组的宝贵的编程实践机会,让我们能够借此机会学习更多的知识,这可以算是一笔宝贵的财富了。
总结——我们的一些工作
1.1 帮助完善中文翻译版本(找到了中文翻译中的几处错误):
再次给出中文翻译地址:Optical Character Recognition (OCR)
以下是我们找到的错误:
1.简介
原译文:本章将带你了解一个基于智能神经网络的(ANN)的数字识别OCR系统是如何运作的。
应该是:本章将带你了解一个基于智能神经网络(ANN)的数字识别OCR系统是如何运作的。
2.什么是人工智能
原译文:机器学习就是使用大量数据进行模式识别系统的训练。 用于训练的数据集可能有两种:一种是示踪的,是说根据输入限定系统的期望输出,也就是对于某种输入有人为的期望结果; 一种是非示踪的,也就是说对系统的期望输出没有限制。 使用非示踪数据集的算法被称作非监督式算法,使用示踪数据集的算法则被称作监督式算法。
应该是:我个人倾向认为:labelled应该翻译为“有标记的“,而不是”示踪的“。unlabelled应该翻译为”未标记的“,而不是”非示踪。[1]
3.简单的界面(orc.html)
原译文:简单的界面(orc.html)
应该是:简单的界面(ocr.html)
[1] 周志华. 机器学习 : = Machine learning[M]. 清华大学出版社, 2016. (第293页 第十三章 半监督学习)
其他
其他的也不多说了,这篇文章写出来,我搞了整整一个下午加晚上,虽然很充实,但是有点累。
对应资源的下载,我都给了相应的地址链接,感兴趣的同学自己可以去下载一下,有问题随时交流(可评论)。
写作时间:2018-07-04