《500 Lines or Less》经典开源程序OCR——探索修改之旅(附程序源码)

摘要

读者们好,本文希望以平实细致的语言,向读者描述以下内容:
  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架构,因为用户界面是直接展示在网页上的,如图(主界面):

![这里写图片描述](https://img-blog.csdn.net/20180704205703373?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图一 OCR主界面
   主界面设计简单简界,总共有6个元素。 1)一个标题:也就是OCR demo 2)一块画布:用html canvas 元素画出来的200*200像素的画布(但是,由于网页中的一个像素实在太小了太难看清,所以作者用网页中的一个10*10像素的方块代表我们OCR识别中的一个“像素单位”,所以:这样一个200*200像素的画布在我们OCR处理的时候就变成了20*20像素的画布啦) 3)Digit输入框:当你要手动添加训练样本的时候,你要先在画布上画一个数字,然后在这个输入框输入对应结果,比如你画了一个1,你就要在这里输入1,相当于训练样本中的label(标签) 4)Train按钮:点击之后会发送数据到服务端(用python文件写的),服务端会对这些新样本进行训练

这里写图片描述

图1.2.1 Train功能(先画数字,输入digit)
![这里写图片描述](https://img-blog.csdn.net/20180704205905146?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图1.2.2 Train功能(点击train)

5)Test按钮:这是一个测试按钮,你要先在画布上画一个数字,然后点击test,网页会弹出一个结果

![这里写图片描述](https://img-blog.csdn.net/20180704210007659?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图1.2.3 Test功能(先画一个数字)
![这里写图片描述](https://img-blog.csdn.net/20180704210028948?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图1.2.4 Test功能(点击test按钮,后台识别之后会让网页返回结果)
6)Reset按钮:点击reset,画布就会重置。

1.3 OCR的程序结构

![这里写图片描述](https://img-blog.csdn.net/20180704210142567?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图1.3.1 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看上去很容易,但是非常费时间,毕竟没有基础。下面直接展示修改过后的网页:

![这里写图片描述](https://img-blog.csdn.net/20180704210416553?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图2.1.1 网页上半部分
![这里写图片描述](https://img-blog.csdn.net/20180704210438953?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图2.1.2 网页上半部分

修改了很多地方。
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三个文件。

![这里写图片描述](https://img-blog.csdn.net/20180704210517693?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图2.3.1 点击Show one sample按钮(1)
![这里写图片描述](https://img-blog.csdn.net/2018070421052997?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图2.3.2 点击Show one sample按钮(2)
![这里写图片描述](https://img-blog.csdn.net/20180704210538210?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图2.3.3 点击Show one sample按钮(3)

2.4 添加功能——对用户上传的图片(含英文文字)进行文字识别,并在网页上显示识别结果

![这里写图片描述](https://img-blog.csdn.net/20180704210622726?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图2.4.1 点击upload image按钮,上面是预览图片,下面是识别的结果。
![这里写图片描述](https://img-blog.csdn.net/20180704210628827?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTI3ODI2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
图2.4.2 点击upload image按钮,上面是预览图片,下面是识别的结果(多行文字)。

这个功能实现要安装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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值