第十一章,图像处理和文本认证

来源:互联网 发布:sql 约束类型 编辑:程序博客网 时间:2024/05/16 12:33

第十一章、图像处理和文本认证

从谷歌的自动驾驶汽车到自动售货机识别假币,机器视觉是一个具有深远的目标的意义的领域。在本章中,我们将专注于该领域的一个很小方面:文字识别,具体通过使用各种Python库来识别和使用在线的文本图像。

使用图像代替文本是一个常用的拒绝机器人来访问和阅读的技术。当邮件地址是部分或者完全呈现为图像时,这时就经常在联系人表单看到。取决于它是如何巧妙的完成,它甚至可能不被人类阅读器察觉到,但是机器人阅读这些非常的困难并且技术足以组织收集你电子邮件地址的大部分垃圾邮件发送者。

使用验证码的事实使得用户可以安全的读取图像,但是大多数机器人不能。一些验证码是比其他的更困难,我们将在本书的后面解决这个问题。

但是验证码不仅仅是在网页上的爬虫需要从图像到文本的转换协助用到。即使在这个时代,许多文件都是简单的从硬盘扫描,然后存在网页上,大多数互联网关心的是使这些文件无法访问,虽然它们是“隐藏在众目睽睽之下”。没有图像到文本功能,这些文件访问的唯一途径仅仅是人类手动输入这些——没有人有时间做这个。

图像转换成文本被称为光学字符识别(Optical Character Recognition)或称ORC。这里有一些库可以执行ORC,许多其他库都支持它们,或者建立在它们顶层。有时系统库会相当复杂,所以我建议你在尝试任何联系之前,先阅读这一章的下一节。

库的概述

Python对于图像处理和阅读是一个梦幻语言,基于图像的极其学习甚至是图像处理。虽然有大量的库可以用于图像处理,我们将集中在两个:Pillow和Tesseract。

这两者都可以从它们的网站下载源码安装或者使用一个第三方Python安装器比如pip分别使用关键字“pillow”和“pytesseract”。

Pillow

可能Pillow不是功能最全的图像处理库,它有一些你可能需要的功能然后一些除非你在做研究或者在Python中重写Photoshop才不需要的功能,或者类似的事情。它也是有良好文档记录非常容易使用的代码。

取消了Python2.x中的图像库(PIL),Pillow像它前身一样增加了支持Python3.x,Pillow可以让你轻松的导入和通过各种接口处理图像,图像掩模(image mask)和偶数像素的特定变换:

from PIL import Image, ImageFilter

kitten = Image.open("Kitten.jpg")

blurryKitten = kitten.filter(ImageFilter.GaussianBlur)

blurryKitten.save("kitten_blurred.jpg")

blurryKitten.show()

在上面的例子中,图像Kitten.jpg会在默认的图像查看器中添加模糊打开,也将保存模糊状态的图像Kitten_burred.jpg在同一目录。

我们将使用Pillow做图像预处理,使得其更加机器可读。但是正如前面提到的,除了这些简单操作,这里还有很多其他东西你可以和库做。想了解更多信息,请查看Pillow文档。

Tesseract

Tesseract是一个ORC库,由谷歌(一个显然在ORC和机器学习技术众所周知的公司)赞助。Tesseract被公认为是最好的,最准确的,开源的ORC系统。

除了是最准确的,它也极其的灵活。他可以通过训练来识别任何数量的字体(我们将很快看到,只要这些字体内与自身相对一致),它可以扩展到辨认任何Unicode字符。

不同于我们在本书之前用到的库,Tesseract是一个用Python写得命令行工具,而不是一个使用import导入的库。安装完毕后,必须要在Python之外使用tesseract命令来运行。

安装Tesseract

对于Windows用户有一个方便的可执行安装程序。截止这个编写之前,目前的版本是3.02,尽管新版本应该更好。

Linux用户可以通过apt-get安装Tesseract:

$sudo apt-get tesseract-ocr

在Mac上安装tesseract稍微复杂一些,尽管它可以通过第三方安装程序轻松完成,如Homebrew,在第五章用于安装MySQL。例如,你可以安装Homebrew然后使用它安装Tesseract:

$ruby -e "$(cur1 -fsSL https://raw.githubusercontent.com/Homebrew/\

install/master/install)"

$brew install tesseract

Tesseract还可以从项目的下载页面进行安装。

要使用Tesseract的某些功能,比如在这一部分训练软件识别新字符,你还要设置一个新的环境变量,$TESSDATA_PREFIX,让它知道数据文件存在哪里。

你可以在大多数的Linux和Mac OS X系统使用:

$export TESSDATA_PREFIX=/usr/local/share/

注意/usr/local/share/是Tesseract默认的数据位置,当然你应该检查确认你自己安装的情况。

同样在Windows中可以使用下面方法来使用环境变量:

#setx TESSDATA_PREFIX C:\Program Files\Tesseract OCR\

NumPy

虽然在OCR中不是直接需要NumPy,如果你想训练Tesseract识别本章下文介绍的字符的其他字符集或字体。NumPy是用于线性代数和其他大规模数学应用的一个非常强大的库。NumPy能够很好的和Tesseract工作是因为它有很好的数学表达和处理图像同像素的大数组。

同往常一样,NumPy可以使用任何第三方Python安装器,比如pip:

$pip install numpy

处理格式化的文本

运气好的话,你需要处理的大部分文字会很干净和格式化。格式化的文本通常满足几个要求,但这几行可以主观的区别什么是“混乱”,什么是“格式化”。

一般情况下,格式化的文本:

①使用一个标准字体书写(不包括手写字体,草书字体或者过度“装饰”字体)

②如果复制或拍照有着极其清晰的线条,没有复制假象或暗斑点。

③十分符合,没有倾斜的字体

④图像不流失,也没有在图像边缘切断文本或者页边。

有些东西可以固定在预处理。例如,图像可以被转换到灰度,亮度和对比度可以调节,并且图像可以被剪裁和根据需要旋转。但是,如要一些更广泛的训练可能有一些基本限制。请参阅“读取验证码和训练Tesseract”。

图11-1是一个理想化的格式化文本:

你可以在命令行中运行Tesseract读取该文件并将结果写入到文本文件:

$tesseract text.tif textoutput | cat textoutput.txt

输出行是一个有关Tesseract库信息,以表明它正在运行,随后是新创建的textoutput.txt的内容:

Tesseract Open Source OCR Engine v3.02.02 with Leptonica

This is some text, written in Arial, that will be read by

Tesseract. Here are some symbols: !@#$%"&‘()

你可以看到结果大多准确,尽管符号“^”和“*”分别被解释为一个双引号和单引号。但就整体而言,这可以让你相当舒服的阅读文本。

模糊图像的文字,创造一些JPG压缩失真,并增加了轻微的背景渐变,结果变得更糟(如图11-2):

Tesseract主要由于背景梯度几乎无法处理这个图像,产生以下输出:

This is some text, written In Arlal, that"

Tesseract. Here are some symbols: _

注意,一旦背景渐变文本很快就被截断,使文字更难区分,并且每一行最后一个字符是错误的,Tesseract尝试是徒劳无意义的。此外,人为的JPG和模糊使得Tesseract很难区分小写字母“i”大写字母“I”和数字“1”。

这是用Python脚本第一次派上用场来清洁你的图片。使用Pillow库,我们可以创建一个门槛来过滤掉背景灰度,带出文本,使得Tesseract处理的图像更清晰:

from PIL import Image

import subprocess

def cleadFile(filePath, newFilePath):

image = Image.open(filePath)

#Set a threshold value for the image, and save

image = image.point(lambda x: 0 if x<143 else 255)

image.save(newFilePath)

#call tesseract to do OCR on the newly created image

subprocess.call(["tesseract", newFilePath, "output"])

#Open and read the tesulting data file

outputFile = open("output.txt", 'r')

print(outputFile.read())

outputFile.close()

cleanFile("text_2.png", "text_3_clean.png")

得到自动创建的text_2_clean.png图像,在图11-3中显示:

除了一些难以辨认或者丢失的标点,至少给我们的文字是可读的。Tesseract给我们它最好的镜头:

This us some text‘ written In Anal, that will be read by

Tesseract Here are some symbols: !@#$%"&'()

句号和逗号是这个图片的第一个受害者,现在争论变得非常小几乎消失,无论从我们的视角还是Tesseract的。另外还有不幸误解“Arial”为“Anal”,Tesseract把“r”和“i”解析成了单个的“n”。

不过,这是前一个近一半文字是隔断的改进。

Tesseract最大的弱点似乎是不同亮度的背景。Tesseract算法尝试在阅读文本之前自动调整图像的对比度,但你也许可以自己用一个工具来得到更好的结果,比如Pillow库。

你因该在向Tesseract提交图片时候明确修复那些倾斜,大面积非文本内容,或者其他问题。

在网站的图片上抓取文本

使用Tesseract在硬盘上读取图片文字似乎并不是另人兴奋的,但它可以作为网络爬虫一个非常强大的工具。图像在网站中可以不经意混淆文本(像本地餐厅网站上的菜单的JPG副本),但他们也有意隐藏文本,正如我将要在接下来例子中展示的一样。

虽然亚马逊的robots.txt文件运行爬虫抓取网站的产品页面,但是书的预览通常不会通过机器人得到回复。这是因为图书预览经由用户触发的Ajax脚本加载,并且图片被小心的隐藏在divs层;事实上,对于一般的网站访问者,他们看起来可能更像一个Flash演示而不是图像文件。当然,即使我们能够得到图片,还有像文本一样读取他们也不是小事。

下面的脚本来完成这一壮举:它定位到托尔斯泰的战争与和平的大印刷版本1,打开阅读器,收集图片的URLs,然后从每一个文本系统的下载,阅读和打印。因为这借鉴了前面章节代码的多个概念相对复杂。我已经在各处添加评论,使之变得更容易理解这是怎么回事:

import time

from uellib.request import urlretrieve

import subprocess

from selenium import webdriver

#创建一个新的Selenium驱动

drive = webdrive.PhantomJS(excutale_path='<Path to Phantom JS>')

drive.get("http://www.amazon.com/War-Peace-Leo-Nikolayevich-Tolstoy/dp/1427030200")

time.sleep(2)

#点击书上的预览按钮

drive.find_element_by_id("sitbLogoImg").click()

imageList=set()

#等待页面加载

time.sleep(5)

#当右箭头可以点击,转到此页面

while "pointer" in drive.find_by_id("sitbReaderRughtPageTurner").get_attribute("style"):

drive.find_element_by_id("sitbReaderRightPageTurner").click()

time.sleep(2)

#获取已加载的新页面(多个页面可以一次加载)

#重复的将不被添加到元组

pages = drive.find_element_by_xpath("//div[@class='pageImage']/div/img")

for page in pages:

image = page.get_attribute("src")

imageList.add(image)

drive.qiut()

#开始通过Tesseract处理我们收集到的图片的URLs

for image in sorted(imageList):

urlretrive(image, "page.jpg")

p = subprocess.Popen(["tesseract", "page.jpg", "page"],

stdout=subprocess.PIPE, stderr=subprocess.PIPE)

p.wait()

f = open("page.txt", "r")

print(f.read())

正如我们前面经历的Tesseract读取,这会完美大打印书的大段,正如在第六页的预览看到一样:

6

“A word of friendly advice, mon

cher. Be off as soon as you can,

that's all I have to tell you. Happy

he who has ears to hear. Good-by,

my dear fellow. Oh, by the by!” he

shouted through the doorway after

Pierre, “is it true that the countess

has fallen into the clutches of the

holy fathers of the Society of je-

sus?”

Pierre did not answer and left Ros-

topchin's room more sullen and an-

gry than he had ever before shown

himself.

但是,当本书的文本前后被彩色背景覆盖时,它变得不可理解:

WEI‘ nrrd Peace

Len Nlkelayevldu Iolfluy

Readmg shmdd be ax

wlnvame asnossxble Wenfler

an mm m our cram: Llhvary

— Leo Tmsloy was a Russian rwovelwst

I and moval phflmopher med lur

A ms Ideas 01 nonviolenx reswslance m 5 We range 0, “and”

当然,你可以选择使用Pillow库清洁图片,但是这对于尽可能人类自主的设计来说可能是一个劳动强度极其大。

下一节讨论了另一种来解决文本损坏问题的方法,特别是你不介意在训练Tesseract前面投入一点时间。通过提供给Tesseract一个巨大集合的已知数值的文本图片,Tesseract可以被“教”在未来更大精度和准确度的去识别相同的字体,甚至有背景和定位问题的文本。

读取验证码和训练Tesseract

尽管“验证码”对于大部分人是熟悉的,更少的人知道它代表什么:全自动区分计算机和人类的图灵测试(Computer Automated Public Turing test to tell Computers and Humans Apart)。其笨拙的缩写暗示了其相当笨重的作用,完全阻碍其他方面可用的网络接口,人类和非人类的机器人往往很难解决的验证码测试。

图灵测试最初是由阿兰图灵1950年在它的论文“计算机器与智能”中提出。在论文中,他描述了一个人类在电脑终端可以同人类和人工智能程序进行通信的安装程序。如果人无法从一个人工智能程序偶然的交谈中区分出人类,就是说这个人工智能程序通过了图灵测试,这是图灵的人工智能的理由,是真正的“思考”了所有的意图和目的。

讽刺的是,在过去的60年中,我们使用这些测试来测试机器,用机器来测试我们自己,结果好坏参半。谷歌的老大难问题reCAPTCHA,目前最流行的具有安全意识的网站,25%的合法的人类用户通过它访问网站。②

大多数其他的验证码系统都比较简单。例如,Drupal,一个流行的基于PHP的内容管理系统,有一个流行的验证码模块,可以生成不同难度的验证码图像。默认的图像看起来像图11-4:

与其他的验证码相比,是什么让这个验证码很容易让人和机器阅读?

①字符彼此不重叠,也不会越过对方的水平方向。也就是说,它可以绘制围绕每个字符的整齐矩形,不重 叠任何其他字符。

②没有背景图像,线条或者其他混淆一个OCR程序注意力的垃圾。

③虽然这个图像并不明显,但是这个验证码使用也有对字体的一些变化。它交替使用干净的无衬线字体( 比如看到的“4”和“M”)和笔迹样式字体(如字符“m”,“C”和“3”)。

④白色背景和深色字符之间有很高的对比度。

这个验证码确实有几个方面对OCR程序有一些挑战:

①字母和数字的使用,增加了潜在的字符数。

②字母的随机倾斜可能会迷惑OCR软件,但人们很容易阅读。

③相对陌生的手写体呈现特别的挑战,需要额外的代码在“C”和“3”以及一个不寻常的小的小写字母“m”培训计算机来找到窍门。

当我们在图片上运行Tesseract的命令:

$tesseract captchaExample.png output

我们得到output.txt文件:

4N\,,,C<3

他得到了正确的4,C和3,但它显然不可以在短期内填写验证码保护字段。

训练Tesseract

为了训练Tesseract认识书写体,不管是多么晦涩难懂,难于阅读的字体或者一个验证码,你需要给他每个字符的多个实例。

在这里,你可能要等候一个很好的博客或者电影,因为它是几个小时相当枯燥的工作。第一步是下载多个你的验证码的例子到一个单一的目录中。你编译的例子的数量取决于验证码的复杂性;我用100个示例文件(共500个字符,或者说每个符号有8个例子)作为我的验证码训练,这似乎工作的相当好。

提示:我建议在验证码解决之后命名它代表的图片(即4MmC3.jpg)。我发现这样帮助在大量的文件中第一次快速检查错误——你可以通过缩略图查看所有的文件,针对它的图片名字很容易的对比。还有在后续步骤中这有助于很好的检查错误。

第二步是准确的告诉Tesseract,每个字符是什么和字符在图片中的位置。这包括创建文件盒,用于每个验证码图片。一个文件盒看起来像这样:

4 15 26 33 55 0

M 38 13 67 45 0

m 79 15 101 26 0

C 111 33 136 60 0

3 147 17 176 45 0

第一个符号表示字符,接下来的四个数字表示坐标,图像描述为一个长方形的盒子,最后的数字是“页号”用于训练多页文档(0对我们来说)。

很显然,这些盒子文件手动创建不好玩,但是有很多工具来帮你解决。我喜欢在线的工具Tesseract OCR Chopper,因为它不需要安装或者额外的库,运行在有浏览器的机器上,并且相当容易使用:上传图片,如何你需要额外的盒子,点击底部的“add”按钮,如果需要,调整盒子的大小以及复制粘贴你的新盒子文件到一个新的文件。

盒子文件必须保存为纯文本,文件扩展名为.box。和图像文件一样,通过它们代表的验证码解决方案很方便的命名盒子文件(例如,4MmC3.box)。同样,这可以很容易的仔细检查.box文件文本的名称,如果你通过它们的文件名在你的数据目录中排序,然后再次与图像文件之间配对。

同样,你需要创建100个这样的文件确保你有足够的数据。此外,Tesseract偶尔会丢弃文件作为不可读,所以你可能在此基础上要一些缓冲区间。如果你发现你的ORC效果没有你想的好,或者是Tesseract被某些字符困扰,创建额外的训练数据和重复测试是一个很好的调试步骤。

创建数据文件夹充满.box文件和图像文件之后,在做任何进一步操作之前复制这些数据到一个备份文件夹。虽然在这个数据上运行训练脚本是不可能删除任何东西,当数小时的工作价值附加到.box文件创建是防患于未然。此外,这很好的删除已编译的混乱数据并且再一次尝试。

这里有半打的步骤来执行所有的数据分析和创建Tesseract所需的训练文件。这里有工具可以给你相应的源图像和.box文件,但是遗憾的是此刻并没有Tesseract3.02的。

我已经用Python写了一个解决方案,可以操作包含图像和盒子文件,并且自动的Chau你感觉爱你所有必要的培训文件。

这个方案的主要设置和步骤能够在main和runAll方法中看到:

def main(self):

languageName = "eng"

fontName = "captchaFont"

directory = "<path to image>"

def runAll():

self.creatFontFile()

self.cleanImages()

self.renameFiles()

self.extractUnicode()

self.runShapeClustering()

self.runMfTraining()

self.runCnTraining()

self.createTessData()

你只需要在这里设置三个相当简单的变量:

languageName:

三个字母语言是Tesseract使用理解看起来是那种语言的。在多数情况下,你可能会想到“eng”是英语。

fontName:

这个名字让你选择字体。这可以是任何东西,但必须是单次没有空格。

directory:

包含所有的图像文件和盒子文件的目录

我建议你使用绝对路径,但如果你使用相对路劲,它相对的是你在哪里运行Python代码。如果它是绝对的,你可以在机器的任何地方运行代码。

让我们来看看使用的各项功能。

createFontFile创建一个必须的文件font_properties,让Tesseract知道我们创造的新字体:

captchaFont 0 0 0 0 0

这个文件包含字体的名称,随后的1和0表示是否斜体,加粗或者考虑其他版本的字体(这些训练字体的属性是一个有趣的练习,但不幸的是这在本书的讨论范围之外)。

cleanImages创建图像文件的更高对比度的版本,装换为灰度,并执行其他操作,使得图像文件更容易被OCR程序阅读。如果你正在处理验证码图像的视觉垃圾,很容易在后期处理中过滤,此处是添加额外处理的地方。

renameFIles重命名所有的.box文件以及Tesseract需要的对应的图像文件的名字(文件数目在这里是连续的数字,以保持多文件区分):

<languageName>.<fontName>.exp<fileNumber>.box

<languageName>.<fontName>.exp<fileNumber>.tiff

extractUnicode看起来在所有的.box文件上,并确定可以用来训练的总的字符组。由此产生的Unicode文件会告诉你发现了多少不同的字符,如果你丢失了什么,这是一个很好的方式来快速查看。

接下来三个功能,runShapeClustering,runMfTraining和runCtTraining,分别创建shapetable,pfftable,和normproto文件。这些都提供了关于每个字符的几何形状的信息,以及提供Tesseract统计信息用于计算给定一个给定字符是这种或者另一种的概率。

最后,Tesseract重命名每个编译数据文件夹是由需要的语言名称预先考虑(例如,shapetable被命名为eng.shapetable)和编译所有文件到最后的训练数据文件eng.traineddata。

唯一一个需要你手动执行的是在LInux和Mac中使用下面命令将创建的eng.traineddata文件移动到你的tessdata根文件夹:

$cp /path/to/data/eng.traineddata $TESSDATA_FREFIX/tessdata

按照这些步骤,你应该没有任何Tesseract训练解决验证码类型的问题。现在,当我询问Tesseract阅读实例图片时,得到了正确的回应:

$ tesseract captchaExample.png output;cat output.txt

4MmC3

成功了!对以前图片解读“4N\,,,C<3”的一个显著改进。

这只是Tesseract的字体训练能力内容中的一个简单的概述。如果你对Tesseract训练有广泛的兴趣,也许开始你的验证码培训库,或与世界分享新字体识别能力,我建议你阅读文档。

转载请注明出处http://blog.csdn.net/qq_15297487




0 0
原创粉丝点击