一文讲通OCR文字识别原理与技术全流程(科普版)

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第3篇文章,点击查看活动详情


一、好话说在前头,谁适合读本文?

本文的作者在教育行业搞OCR识别工作,教育领域的OCR比较复杂,除了文字外,还有图片、表格、公式等等。即便同样是公式,在数学里要斜体,在化学里要正体,这都是行业规范。

本文的读者是谁呢?读者是……最终谁会读,我不知道。但是,我定位以下人群为本文的读者,换句话说,我就是写给他们看的。

1.1 公司领导:节省成本,沉淀技术

很多企业领导,看到OCR属于人工智能范畴,很恐惧。哎呀,我们公司的员工,连正常的业务逻辑都写不好,交付个系统一堆Bug。

现在需要使用OCR功能了,怎么办?买一个吧。不买难道自己做吗?那样,我还要建一个人工智能团队。

这个情况,还真得具体分析。

我了解到有一家公司,他们的OCR识别需求非常简单:仅仅识别0到9,共10个数字。而且,数据来源单一,保证透明背景纯色线条字迹。这种待识别的样本,非常规范

其实,随便找一本图像识别的书,翻开第一章,几乎都是在讲如何识别这类数字,这个例题已经20多年了。这在程序员中,被称为是Hello World级别的程序,是入门的第一课,没有难度。

甚至谷歌公司觉得这太简单了,以至于人工智能受到了侮辱。于是,他们率先把入门的例子,由10个数字,改成了识别“轮船”、“汽车”、“青蛙”、“小鸟”等10类物体。

但是,这家公司依然以30万一年的价格,购买了一个识别数字的OCR服务。

这就像是买了辆大巴车,当电动车来用,一个人开着它走街串巷,维护成本高,利用率也低。

因此,我感觉,领导不需要了解技术细节,但是需要大体了解它的成熟度和行业状态

本文会讲述做OCR的流程,以及每一步需要的资源支持,以便领导们可以盘点资源,量入为出。

1.2 产品经理:了解过程,融会贯通

产品经理经常被开发人员怼。一方面是开发人员性格过于刚直。另外就是产品经理,有时候确实不了解实现过程就乱提需求:比如,App主题色要随手机壳的颜色来变化。

但是,我也见过那种开发出身的产品经理,他不仅懂产品,也懂技术。

他经常把开发人员怼得一愣一愣的:怎么实现不了?这边有数据,那边也有,做一个关联,查询时别不加限制,那样太慢!

开发人员则红着脸,遇到新需求时,先自己百度一下,做完了功课再去找这个产品经理辩论。最后,开发人员沮丧着回来,百度也不靠谱啊,原来是有实现思路的!

因此,我感觉产品经理需要了解技术的实现过程,以便在关键节点上,可以提出产品侧的更优方案

本文会讲述实现OCR需要几个步骤,以及每个步骤的关键点是什么。我觉得产品经理有必要看。

1.3 初级小白:解疑答惑,入门行业

有人觉得OCR好神奇,怎么做到的?我不明白,谁来给我解释解释。这是对此感兴趣的求知者。

也有人,非常喜欢图像识别,自己想学,但是经常会被拒之门外。这是怀有满腔热情和愤懑的技术小白。

网络上,确实有很多大牛,博士硕士研究生,但是因为他们的水平很高,我们很难与他们对话。我曾经被鄙视:一个傅里叶变换,一句话就可以解释清楚,你却写了几千字,说了一堆废话。

于是,我认识到“同等对话”很重要。如果我想要实现小康家庭的生活,那我去找全球商业大亨请教,可能起不到什么效果,反而去跟楼下五金店的老板拉拉家常,能有所收益。

现在,我弄明白了OCR识别。同时,我也想起之前的迷茫和无助。现在,或许还存在很多曾经的我,我要自己帮一下自己。

本文会讲整个OCR的完整流程,以及其中的难点和解决方案(思路以及术语关键词)。如果你是程序员的话,我在专业版里,还有代码详解。

OCR这个行业,如果无法入门,掉头就走,一旦入门,爱不释手。

好了,前言我说完了,也算是导读,如果觉得本文适合你,可以继续往下看了。

二、OCR识别的全流程(科普版)

OCR是一个简称,全称叫Optical Character Recognition,中文是:光学字符识别。

它的本质是:把图像形状转变为文本字符。

下面说一下,我在教育行业是如何应用OCR的。

信息化教学越来越普及,很多教学素材都要搬到信息化平台,比如试卷试题。那么,纸质的试卷要电子化,就会用到OCR识别技术。

这么一张图,需要识别成结构化(图片、文字、公式、表格可独立提取出来)的数据,识别结果如下所示:

而且,识别结果还可以下载成word文档,便于老师校对并进行二次编辑

这就是OCR的一个典型应用。

除此之外,我们常见的各种证件识别、名片识别、车牌识别等,也涉及OCR技术。

我在入门OCR的时候,做过一个小功能,我把它作为一次学习总结和毕业小考,效果如下:

上面这个例子,在github上已经完全开源。此例子基本囊括了OCR的全过程,下面我就以它作为样板,来讲一讲OCR的全流程。

OCR技术的实现,总体上可以分为五步:预处理图片切割字符识别字符恢复版面后处理文字

中间的三步是核心,头尾两步最难。

2.1 预处理图片

我们买回来水果,需要洗一下再吃。如果运气不好的话,还需要挖掉虫眼和糙皮才能吃。我们把吃水果前的这些步骤,叫做CSG(吃水果)的预处理。

在进行OCR之前,也需要对图片进行预处理。因为,一般待识别的图片千奇百怪,来源复杂:有拍照、有扫描、有截图。

拿拍照来说,有夏至那天中午头儿,在阳光直射下拍的;也有人在傍晚,拿着大顶转着圈儿拍的。如果不进行预处理,OCR会很为难,就像你面对刚从粪池里捞上来的大枣一样为难。

2.1.1 光影的预处理

一般情况下,我们定义白色为背景,黑色为字体。

但是,如果图片上有了光影,就会存在模糊状态。说它是背景吧,它不是白色的。要说它是文字吧,黑乎乎地一片儿,也认不出来有什么字符。这导致OCR经常人格分裂,这是……这不是……它是不是呢?智能出现了问题,人工一看,我给做个预处理吧,交给你的时候保证非黑即白,你专心做事就行。OCR很感动。

2.1.2 倾斜的预处理

理想条件下的文档图像,应该是水平的,这样方便切割方块字。

但是,现实世界中,不管是人,还是素材,都很难摆正自己的位置。

不正,切起来就复杂了。治图,如同治人,需要分门别类(强制升华文章格调)。

上面这种倾斜最为常见,处理起来也最简单。只需要几句代码就能搞定,我会在以后专门介绍。基本原理就是找到文本的最小面积矩形(关键词:minAreaRect),然后旋转这个矩形,实现角度矫正,看下面这个动态图。

但是,这种方法有时候也不灵,比如下面这张图。

我们现在框一个矩形,完美!

我们再把矩形摆正,完蛋!

这种倾斜,无论怎么摆矩形都不行,因为矩形区域内的文字又有倾斜!

这时候,就需要用另一种方法,叫做霍夫线变换(关键词:HoughLinesP。有时候搜索一个问题,都不知道该搜啥,此处我提供了关键词,其解决方案可直达灵魂)。

霍夫线变换就是在图上找直线,因为图中的若干点,是可构成一条直线的。把这些直线画出来,你会发现玄机,看下面的动态图。

一段若干行的文本,每一行的字都应该是在一条直线上的。

从结果倒推过程,如果找到了一行直线,那么是不是就找到了一个文本行。

当把这些直线摆正时,就实现了文档的矫正。看下面的动态图。

2.1.3 扭曲的预处理

上面讲的是平面的角度倾斜,此类情况在复印和扫描中较多(纸张放斜了)。

这不算严重,顶多就如同用凉水泡方便面,问题不大。

其实,我们遇到更多的图像是照片。拍照,问题就多了,会存在空间的扭曲。看下面的动态图(图是动态的,如果不是,等一等,或者你遇到盗版的作者了,正版作者是ITF男孩)。

上面的图,问题就比较严重了,就如同用煤油泡方便面,还非得让别人吃,这叫扭曲。

空间的扭曲,体现在视觉上就是远大近小。

我们来矫正下面这张图,这张图应该是站在长城上拍的长廊,越远越小。

肯定能矫正,就是步骤有点多。但是,换算成代码,也不会超过100行。下面这张动态图里,我把每一步对图片处理的方法也都列上了。总共9步,每一步都可以单拉出一篇文章来讲解(写到这里,我想出视频教程了,给我点赞,鼓励我)。

上面的2.1章节部分,讲的都是最基础的预处理操作。

如果你的图片来源很复杂,尤其是包含各种场景下的拍照,或者也有从漫山遍野捡来的野生图片、二手改装图片。那么,你的预处理工作将会比较费劲,没有难点,但是需要耗费人力物力,需要时间

如果,你的图片来源很简单。就像我开头讲的,0到9数字识别还购买OCR服务的例子。他们公司是用电子采集笔在电子方格上写数字,电子方格是统一的,笔是统一的,样本非常标准。这种情况,不需要预处理,直接进入下一步,切割字符(妈呀,这个转场,太丝滑了)。

2.2 切割字符

假设,通过了预处理,我们的图片都变成像下图这样规范。

我忽然想到,我们是要做OCR字符识别的(你……干啥来的)。

于是,我们需要切割字符,把每一个字……都给他(咬着牙,发狠的表情)……挖出来。

为什么要把每个字符都切割出来?因为OCR最终是对单个字符进行识别的(识别26,其实是识别“2”和“6”)。

并且,还需要对每个字符做好标记,因为识别完了,还得还原回去。识别完了,结果是一堆单蹦的“1”、“2”、“3”、“+”、“-”字符。我们需要根据它们的相对位置,还原成“8-7=1”。所以,我们就知道了,哪个题目做对了,做错了,从而给出批改结果。

2.2.1 投影法实现分割

上帝说要有光,就有了光。如果有姓尚的朋友,可以给孩子起名叫:尚有光。

有光以后,当光投过来时,物体的背后就有了影。有影子的地方就有实体,没影子的地方就有空隙。

那位说了(我也不知道哪位),你扯这些干什么?这是三岁小孩子都懂的常识。

没错,三岁小孩子都知道。但是三十岁的大孩子不一定能想到,这个常识可以用来分割字符。

2.2.2 切行

假设我们拿着一根头发丝儿,横着收集像素点,从左侧插入,从右侧推出。把所有黑点都压缩到一起,把黑色素……嗯,黑色素堆到最右侧。就像下面的图这样。

此时,我们就能清楚地知道哪个区域是有文字的行,哪个区域是白纸。这个价值两百五的操作,可以实现行的切分

这一招就是投影大法,三岁孩子都了解。

2.2.3 切列

切行是横着切,切列就得竖着切了。

一定要先切行,再切列。多数情况,行是有行距的,每一行都会有明显的界限。但是列……如果把整个文档做投影的话,基本上就沦陷了。

上面那样做投影,拆不出单个字符。因为一篇文档的字,就像城墙一样,磨砖对缝,无法切分。

但是,换成对一行文本进行投影分析,就可以了。看下面这个图,非常之清晰。

通过投影之间的间隙,我们就可以把每个字符切割开来。

2.2.4 切字

有了行与列切分的方法,相信把字符切出来,应该是不难的。其实就是很简单,代码也不复杂。全都是数组的分析。

那么切出来的字,最终是这样。

不是白纸黑字吗?为什么都变成了黑底白字呢?

其实,这是故意的。为的就是要方便OCR进行识别。我们都知道(也可能不知道),在RGB色值中,0代表黑色,255代表白色。

不管计算机的算力多么强大,一秒钟能运算多少亿万次,它的底层还是二进制,也就是101010。你可以简单地理解成它只认识数字。你看到字母A是A,计算机没有你那么厉害,计算机偷偷地在显示器上输出A这个图案,然后心里暗自记下这个物体是65。

因此,任何文本、图片、音视频,最终都要被解析成数字,这样计算机才能干活。

扯这些有什么用?你在逃避什么?黑白颠倒的问题呢?

别急,马上。我们希望计算机识别图片上的字,而不是背景。所以,把背景置为黑色,也就0,把字符变成白色,也就是255,这样有利于计算机更专注于分析字符的痕迹。因为,0默认是忽略掉的。

你看,说着说着,就谈到了人工智能的机器学习。哈哈,又转场了,真爽。

2.3 识别字符

图片究竟是怎么变为字符的?它还能自己学习。

计算机通过学习一些样本之后,遇到一些从未遇到过的同类样本,也能正确地识别出结果,这很神奇。我想了一夜也没想明白。

第二天,我带着孩子去公园,公园门口有一对大狮子。孩子指着狮子说,狗!我说,哦,那不是狗,那是狮子,跟狗有点像是不是。又走了一段路,公园里又出现一个麒麟的雕塑。孩子指着它说,狮子!我说,那不是狮子。孩子说,是狗。我说也不是狗,它叫:麒麟。我感觉到,孩子的大脑在反向矫正信息,这就是监督学习

当我给他看狗的图片时,我告诉她这是狗。

她根据自己的认知,找了几个特征,构建了一个模型:长嘴+尖牙=狗。

虽然只是看过图片,但是出门遇到真狗,她根据这个模型也认识对了。

后来,她遇到了狮子,她修改了模型:长嘴+尖牙+鬃毛≠狗=狮子。

后来,又遇到了麒麟,这个公式变得越来越复杂……决策项越来越多。

人工智能,就是模拟的人类的神经元,构建神经网络来尝试寻找特征和结果的关系。如果对了,就给这个特征加分。如果,错了,就给这个特征减分。

识别数字,也是一样。

比如在学习识别数字6的时候,它随机认为只要有一个圈圈特征,就是数字6。

验证其他样本时,发现这个随机特征是对的(不对就再换一个特征再试)。于是,它建立了一个模型:只要有圈这个特征,就是6。

后来,这个模型遇到了数字0。加入新样本后,人工智能发现,0也有圈,但它不是6,也有可能是0。得再找一个特征,于是,新增一条,有勾就是6。后来,它又遇到了9。那勾在上面的就是6。后来,它又遇到了字母b……反正计算机有的是算力,能在很短的时间内完成这些学习。上面我是搂着说的,其实即便在32*32像素的小图片上,它随机上几十个特征去做验证,一点都不吃力。

这就是识别字符的原理。具体到代码,也很简单,因为人工智能框架目前已经非常成熟。虽然,这篇是科普版,不是专业版,不适合讲代码,但是我还是非常想贴上一段代码,给大家看看。打破你的认知,人工智能的应用层很简单,别被忽悠了。

举个例子,识别10类常见物体:飞机、自行车、鸟,猫,鹿、狗、青蛙、马、轮船、汽车。

它的核心代码只有……6行。

所以,OCR字符的识别从来不难。难的是两头,比如开头的预处理,以及下面要说的后处理。

2.4 文本后处理

识别出了字符,意义不大,有效地连接起来才能发挥作用。

一定要记住我上面说的这句话,默读3遍以上。

其实,这句话没啥用,只是有助于缓解紧张的气氛!

对于类似的话,我认为是废话,因为没有任何指导意义,但是说的也没错。

2.4.1 版面还原

可能有人会觉得,我接下来讲的会比较跳跃,有点作者着急去厕所的感觉。这并不是什么写作风格,这篇文章我快写吐了,很想快点结束。或许我该搞一个系列专题,我比较喜欢讲述体系化的东西,不喜欢一次冒一个点,那样对别人没有什么深度价值。

也可能有人觉得,版面还原不难(是的,进入正题了),字符我都拆开了,坐标也记录了,把识别的字符画上,不就还原了?!

没错,说的很对,把识别的结果画上去,视觉上是还原了。

但是,这依然属于单个字符识别的那一步,只不过做成了结果可视化,是坐标还原,并不是版面还原。

我们期望的拆分和还原应该是下面这样:

“10+2= 4-3= 5+6=11”这些文本从数据结构上应该是一行。而且,“10+2=”从数据结构上是一个基本单位。因为,我们要对基本单位做运算和批改。这才叫还原,其实并不简单。

有点震惊,我拆字的时候,没有人跟我要求过这些规则。

举个小例子,这个例子非常小,假设你识别出来了2个字,你现在有2个字符的数据:

请问,这两个字,是不是在处于同一行?

你通过肉眼无法判定,得计算。

这就需要你用代码编写算法处理。如果你数学不好,那可能还真的是一个不小的挑战。从图上看,你的眼睛可能几毫秒就识别出来了,但是计算机没有眼睛,只有大脑。它就等着你告诉它要怎么去算什么数据。

其实也好处理(话都让你说了,难也是你说的),看两个字在Y轴的重叠情况。如果重叠达到一定占比,那就可以认为这两组数据是处于同一行。

其实字符与字符之间的关系还有很多情况。

根据情况的不同,我们就可以做不同的判定。

上图所示,如果文本1的矩形区域和公式1的矩形区域,在横向上有一定比例的重叠,那我们可以认为,它们是处于同一行。如果文本2的区域完全包含(重叠率100%)于表格1的区域中,那么我们可以认为文本2属于表格1。同样,文本2文本3在纵向的重叠率,可以作为它俩是否位于同一列的一个指标。

2.4.2 文本校正

OCR识别的最终目的,是要获得一份准确的、结构化的文本内容。

单个字符识别,其实是各自为战,前后不商量。

就比如,遇到一个圆圈形状的字符图片。OCR识别就犯了难,它是数字“0”?汉字“〇”?大写字母“O”?小写字母“o”?中文句号“。”?还是“Q”忘了加尾巴……。

啥都对,啥都不对。

所以,需要矫正……校正。这两个词,都是高频词,尤其拼音打字jiaozheng,容易出错。其实,也好分辨。看语境,如果我前后提到了“文稿”,那么是“校正”的可能性就大。如果我刚刚说了“牙齿”、“视力”、“角度”啥的,那么基本上就应该是“矫正”了。

OCR识别的最后一步校正也是一样。如果无法确定是数字“0”还是字母“o”,可以观察它相邻的几个字符,下面一图胜千言。

单个字符识别不对没关系,后期智能校正可以结合语境来帮你纠正。这个步骤就叫做后处理

我想,OCR流程介绍的差不多了。下面该总结了。

三、总结

其实,我已经迫不及待地想睡觉了。但是,睡觉前,我还是想输出几个观点。

3.1 OCR的投入:自己开发 vs 调用第三方?

需要企业领导视自身业务需求和研发能力来确定。

通过上面的流程讲解,其实我们也了解到,做OCR并不难,这在业界已经非常成熟了。如果,你的业务需求很单一,另外也有一两个喜欢研究技术的程序员(三年经验起),其实可以投入几个人、几个月搞一搞试试看效果。就算不成功,起码他们再跟第三方对接起来,也属于专业级别了。

那么,如果你的业务需求复杂多样,是不是就要用第三方服务了。也不一定,需求太复杂,通用的第三方平台,不一定能满足你的个性化需求。我之前遇到过一个例子,也是在教育行业。他们有一个场景是用在填空题手写答案上。一般的手写识别,你就算写的80%正确,它会给你智能纠正,输出字符。但是,教育行业不行,写错了就是写错了,不要纠正。比如,武术的“武”,学生如果右下角写成了“戈”那样多了一撇,不要输出“武”,要输出不是字,并记录下学生的错字图片。这一下,没有一家平台可以对接。其实,自己研发是可以做到的。但是,研发这玩意有什么用?只有自己用。

如果业务比较通用,且第三方费用不是很高的情况下,可以考虑购买服务。其实,不管是个人生活还是企业运转,总归都是要考虑成本的控制。最终都是资金限制了一切。所以,我说多少都是白扯。那种说,我有钱,但是找不到人才的老板,请联系我。

3.2 OCR的重点在哪里?

我认为是数据。

现今而言,瓶颈已经不是技术了,数据量决定识别率。短期内,技术没有太多可提高的空间了。剩余的就是拼数据量。

很多人觉得人工智能不智能,甚至智障。其实,有一部分原因就是训练数据太少。就拿智能问答来说,很多人问的问题,人工智能回答不好。原因就是,你问的这些问题它从来没有接触过。

就像我和孩子去公园的例子,我一直给她看狗的图像,突然问她麒麟是什么,她会从狗的答案里去找类似的应对。

我还是拿教育行业举例(我熟啊),如果我们拿一本鲁教版七年级地理上册,交给人工智能学习。如果它学完了,你问它书本上的知识,它绝对是回答准确。但是,你如果问它七年级下册的,它估计就蒙了。更何况,还有八年级、九年级呢?更何况学科还有物理、化学、生物呢?更何况,我们生活化的对话场景,不会出现在课本里呢!想让它聪明,得多少数据,谁又有这些数据?!

OCR也是一样。识别那一块儿,大人写的字和小孩写的字,是有差别的,想要识别准确,肯定是样本越多越准确。后处理校正那一块儿,无他,只能是见多了才能识广。

3.3 非得凑够三条吗?

有人说,你讲总结,最好不要超过三条,多了记不住。

但是,如果不够3条呢?也不用凑。

本文写了不少。是否对大家有帮助,现在还不好说。这得看大家的反馈了。

我曾经写过一个Android开发的专栏。

但是,大家对于Android开发其实并不看好,阅读量少,而且大家也嘲讽现在居然还有人学Android。那我写这个专栏,其实帮不到很多人。也就是,没有需求。那我完全可以投入同等精力,去写另一个受众更广的专栏。

对于OCR相关的题材,我有知识储备,包括github也开源了上面的自动批改项目。至于大家是否有需求,这个是无法预测的。我也会根据文章的阅读和互动情况,调整后续的内容输出。

是再出一篇专业版文章,还是出一系列专题,或者是不再更新。也希望大家给我一些反馈。

本文作者掘金@ITF男孩,禁止私自转载,侵权必究。

猜你喜欢

转载自juejin.im/post/7147218078923751455