2022.08.12开始学习最后一章!
2022.08.13继续学习
2022.08.14继续学习
2022.08.15继续学习
2022.08.16继续学习
2022.08.18继续学习。结束十八章!
我们希望计算机能够读出照片中的文字,这样一来,如果我们之后想找到这张照片,我们就只需要输入照片中的文字: L U L A B ′ s A N T I Q U E M A L L \rm LULA\ \ B's\ \ ANTIQUE\ \ MALL LULA B′s ANTIQUE MALL,计算机就能自动找出这张图片,这样我们就不用花大量时间把相册翻个底朝天,从千百张照片中把它找出来了。
O C R \rm OCR OCR 所要做的事情有如下几个步骤:
虽然现在 O C R \rm OCR OCR (或者说光学文字识别)对于扫描文档来说已经是一个比较简单的问题了,但对于数码照片来说,现在还是一个很难的机器学习问题,如果能够成功实现它,不仅可以帮助计算机更好地理解图像中的内容,还可以开发出一些比如能够帮助盲人的应用,举个例子,可以为盲人提供一种相机,该相机可以看出来它们前面有什么东西,然后直接告诉他们,他们前面有个路牌,现在也有研究人员将照片 O C R \rm OCR OCR 技术应用到汽车导航系统中,比如说我们的车能读出街上的路牌,帮我们导航到目的地。
1. T e x t d e t e c t i o n 2. C h a r a c t e r s e g m e n t a t i o n 3. C h a r a c t e r c l a s s i f i c a t i o n \begin{aligned} &1.\ \rm Text\ \ detection\\ &2.\ \rm Character\ \ segmentation\\ &3.\ \rm Character\ \ classification \end{aligned} 1. Text detection2. Character segmentation3. Character classification
为了实现照片 O C R \rm OCR OCR ,这是我们能做的:
首先我们要扫描图像,并找出有文字的图像区域,比如这就是一个 O C R \rm OCR OCR 系统可能识别到的一个文字区域(下图);
然后它会得到这个矩形区域,然后进行文字分离,通过这个文本框它会识别出 A N T I Q U E M A L L \rm ANTIQUE\ \ MALL ANTIQUE MALL,然后将其分割成一个个独立的字符区域;
分割好这些独立的字符后,我们用一个分类器,它会对这些可见的字符进行识别,然后识别出第一个字母是 A \rm A A,第二个字母是 N \rm N N,第三字母是 T \rm T T 等等,做完这些之后,可能我们就能计算出这句话是 L U L A B ′ s A N T I Q U E M A L L \rm LULA\ \ B's\ \ ANTIQUE\ \ MALL LULA B′s ANTIQUE MALL,然后图片中其它有文字的地方也是一样的方法。
实际上有一些照片 O C R \rm OCR OCR 系统会做一些更复杂的事情,比如最后会进行拼写校正,举个例子,假如我们的字符分割和分类系统识告诉我们它识别到的字符是 C 1 e a n i n g C\red 1eaning C1eaning,然后一些拼写修正系统就会告诉我们这应该是单词 C l e a n i n g C\red leaning Cleaning,我们的字符分类算法把字母 l l l 识别成了数字 1 1 1,不过由于本节暂时不考虑这些东西,所以忽略掉最后一步,我们只关注系统的前三步:文字检测(Text detection)、文字分割(Character segmentation)以及字符分类(Character classification)。
图像 O C R \rm OCR OCR 流水线的第一步是文字识别,比如我们看这样一张图(下图左), 然后尝试找到图片上文字出现的区域:
文字识别在计算机视觉中是一个比较难的问题,因为根据我们找到的这些文字区域,它们对应的矩形具有不同的长宽比例,所以为了讲述如何在图片中检测它们,我们首先从一个简单点的例子开始,即行人检测,之后我们再将做行人检测的思路应用到文字识别中去。
在行人检测中,我们有一张类似这样的图片(上图右),我们要找出图片中的各个行人,我们会依次找到六个行人,这个问题与文字识别相比,简单的地方在于我们要识别的东西具有相似的长宽比,仅用一个具有固定长宽比(fixed aspect ratio) 的矩形就可以了(长宽比的意思就是矩形长度和宽度之间的比例),这些行人们的长宽比都是差不多的。对于文字来说,不同位置的文字具有不同的比例;对于行人检测,尽管不同行人距离摄像头的距离可能不同,所以这些矩形的高度根据不同行人的位置也会不一样,但比例还是不变的。
为了建立一个行人检测系统,我们需要这么做,例如我们决定要把比例的标准定为 82 × 36 82×36 82×36,当然我们也可以选择其他的相近的数字,比如 80 × 40 80×40 80×40,或者 82 × 36 82×36 82×36 也可以,我们将要做的是从数据集中收集一些正样本和负样本,这里是一些 82 × 36 82×36 82×36 的图片样本,其中包含了整个行人,还有一些不包含行人的图片:
上图我们展示了 12 12 12 个 y = 1 y=1 y=1 的正样本,还有 12 12 12 个 y = 0 y=0 y=0 的负样本。在一个更典型的行人检测应用中我们可能会有 1000 1000 1000 个到 10000 10000 10000 个数目的样本,甚至更多,如果我们能得到更大的数据集的话,然后我们可以在我们的网络中训练或者使用其它学习算法,向其中输入一个 82 × 36 82×36 82×36 的图块,来对 y y y 进行分类,来划分每个图块是否包含一个行人,于是这给了我们一个应用监督学习的方法来对一个图块进行处理判断其是否包含有行人。
现在假设我们得到一张新图,比如这样的一张测试集图片(下图),我们尝试在图片中找到一个行人,首先在图片中选取一个矩形块,像这样的(下图左上绿色方块)一个 82 × 36 82×36 82×36 的图块:
我们把这个图块传递给我们的分类器,来检测图块中是否有行人,这时我们的分类器应该会返回 y = 0 y=0 y=0,因为上面没有行人,接下来将绿色的矩形稍稍移动一点,再把这个图块传递给我们的分类器判断是否是行人,在这之后,我们再次将窗口向右滑动一些,再传给分类器进行分类判断。这个绿色矩形每次移动的距离是一个参数,一般称之为步长(the step size of the parameter),有时也被称为滑动参数(the slide parameter),如果我们一次移动一个像素,那么步长就为 1 1 1,一般这个步长表现最好,但是计算成本较高。一般来说,把步长设为 4 4 4 像素或 8 8 8 像素或更大的数是比较常见的。这就意味着矩形每次都会移动一些。继续这个过程,继续向右移动矩形,每次都移动一点,每次移动都使用分类器对图块进行分类,一直这样下去,直到在图中各个位置都过一遍(下方动图),首先从第一行开始,再移动到图像的下一行,就这样遍历图中所有不同的位置并且通过分类器进行分类。
它是一个很小的矩形,且它只会检测某个特定大小的行人,接下来我们要做的是使用更大的图块,进行和使用小图块时相同的操作,我们所说的用更大的图块实际上意思是:当我们选取完这样的图块之后我们要做的是把这个图块调整到 82 × 36 82×36 82×36 的大小,所以把这个大的图块调整为一个更小的图片,然后把调整后的图片传递给我们的分类器中,然后判断是否有行人。
最后我们还可以使用更大尺寸的窗口来把图像过一遍。经过这一系列过程后,算法便能够检测出图中各个地方是否出现行人(上图)。
这就是我们如何训练一个监督学习分类器,然后使用一个滑动窗口分类器或者说滑动窗口检测器来找出图中的所有行人。
让我们回到文本检测的例子,谈谈 O C R \rm OCR OCR 流水线中的这个阶段,也就是如何找出图中的文字区域,与行人检测类似,拿出一系列包含正样本和负样本的训练集,其中正样本代表的是对应的区域有文字出现,之前我们做的是行人检测,但是现在我们要尝试做文本检测,所以正样本代表的是含有文字的图块,负样本表示的是没有文字的图块。
训练完之后,我们可以将其应用在一个新的测试集中的图片上,这是我们刚才作为例子所用的图片(下图1),现在我们在这个图片上来运行算法,我们将使用一个固定比例的滑动窗口来进行讲解。
这里我们将只使用一个固定大小的矩形,假如说,我们在这些图块上使用这样的(上图1左上绿色方块)滑动窗口分类器,这样的话,我们就会得到这样的结果(上图2、3),其中白色区域表示检测系统发现了文本,黑色区域表示分类器没有发现文字。同时我们发现,有很多白色的区域,这表示分类器在这些位置上发现了文本,我们在图2中所做的操作是用白色表示分类器认为有文字的地方,而这些深浅不同的灰色对应的是分类器认为该处有文字的概率,所以这些灰色阴影意味着分类器认为它可能找到了文本,但是概率不高,而这些亮白色的区域表示分类器输出了一个很高的概率,也就是该处有文字的概率。
但到这里还没有结束,我们真正想做的是在所有文字周围绘制矩形,然后更进一步将这些分类器的输出应用到一种叫做放大算子(expansion operator) 的东西上,它所做的是取这里的图,它把每个白色方块或者说是白色区域,然后扩大这些白色区域,我们可以用数学方式来实现它,如果我们观察图3,构造这个图像的方法,就是对图2的每个像素判断其一定范围内是否存在白色的像素,如果某个像素,它周围 5 5 5 到 10 10 10 个像素的范围内,如果存在其它的白色像素,那么就在上图中把整个范围内的像素都变成白色,这样做的效果是,把上上图中的每个白色区块都扩大一些,都增长一些,通过检查像素附近是否存在白色像素,然后把这一范围内都变成白色。
在完成之后,现在我们看看图3的关联部分,也就是白色区域,然后在其周围绘制边框。如果观察所有白色区域,我们想用一个简单的方法来排除那些比例很奇怪的矩形,因为我们知道文本周围的框宽度应该远大于高度,所以如果我们忽略瘦高的矩形,类似这些(上图3蓝色标注),我们丢弃这些太高太窄的矩形,我们在那些长宽比例正常的文字区域周围画上矩形,即文字区域周围的这些框框(上图3红色方框),对应商场的招牌 L U L A B ′ s A N T I Q U E M A L L \rm LULA\ \ B's\ \ ANTIQUE\ \ MALL LULA B′s ANTIQUE MALL、 L U L A B ′ s \rm LULA\ \ B's LULA B′s 标志以及 O p e n \rm Open Open 的标志,这个例子中其实遗漏了一段文字,虽然很难看出来,但这里是有一块文字的(上图1紫色标注),它对应的是这个区域(上图3紫色标注),但它的长宽比看起来是错的,所以被我们丢弃了。
看起来效果还不错,但是在该例中,我们的分类器还是遗漏了一段文字,它很难被看出来,因为这些文字写在了透明的窗户上。这就是使用了滑动窗口的文本检测系统,通过找出这些包含文字的矩形,现在可以把这些区域剪切出来,然后进入流水线的下个阶段,也就是识别文本。
现在回一下流水线的第二步是字符分割,给定下图所示的图片,我们如何分割出图像中的单个字符?我们要做的是再次使用监督学习算法,用一些正样本和一些负样本。
现在我们观察这些图块,然后判断出图块中是否存在文字分割的地方,所以对于初始的正样本,对于第一个样本,即这个图块(上图1),看起来它和中间确实存在两个字符分割的地方;第二个样本看起来也是一个正样本(上图2),如果我们在正中间放一条线来分割字符好像是可以的,所以这些都是正样本(上图左),它们的中间代表两个字符之间的分隔。对于负样本,我们不需要把字符从中间分成两个,所以这些都是负样本(上图右),因为它们并不表示两个字符的分割。
所以我们要做的是训练一个分类器,可能会用到新的网络,也可能使用不同的学习算法,来尝试将正样本和负样本进行区分,训练完这样的分类器后,我们可以将它运行在文字检测系统输出的这些文本中。我们先来看看这个矩形(上图3对应绿框),我们可能会问,它看起来像是绿框的中间部分吗,它看起来像是两个字符的分割吗?这时分类器会说不,然后我们移动矩形,这时一个一维的窗口分类器,因为我们只在一条直线上滑这个窗口,简单地从左向右,只有这一行而没有其他行,但是分类器到这个位置时(上图4对应蓝框),这时我们问,我们是否应该分开这两个字符,或者说我们是否应该对矩形中间进行分割呢,分类器将会输出 y = 1 y=1 y=1,这种情况下我们会决定在中间合适的位置画一条线来分割这两个字符,然后再次移动窗口,不断地重复该过程,判断正负样本,我们每移动一次就使用一次分分类器,它会告诉我们应该在哪里对字符进行分割,直到把图像全部分成单独的字符。再次重复一下,这是一维的滑动窗口用来进行字符分割。
这就是 O C R \rm OCR OCR 识别流水线的全部,在本节中我们已经谈到了文本检测步骤,其中我们使用滑动窗口检测文本,我们也使用一个一维的滑动窗口来做字符分割,将这张图片(上图中)分割成单个文字,那么流水线的最后一步就是文字识别,可能你早已经熟悉这一步了,因为在之前监督学习的章节中你已经能应用一个标准的监督学习算法到你的网络或者其它东西中了。为了能处理输入的图片,训练一个分类器,可以分类 26 26 26 个字母,或者我们可能有 36 36 36 个字符,如果包含数字的话,这是一个多分类问题,即输入一个包含文字的图片,它能判断图片中的字符。
这就是图片 O C R \rm OCR OCR 流水线以及使用类似于滑动窗口这样的思想来组合这些不同的组件开发出图片 O C R \rm OCR OCR 系统。接下来的章节中,将继续研究图片 O C R \rm OCR OCR 问题,将围绕构建一个这样的应用来探索一些有趣的问题。
为了引入人工数据合成这个概念,我们用字符识别这个例子来讲解,也就是照片光学字符识别 O C R \rm OCR OCR 的一部分,我们输入图像,就能识别出字符。
假如我们收集到了一个大的标签数据集(下图左),在本例中,我们选用了一个正方形的长宽比,所以我们要对正方形图像块进行识别,目标是输入一个图像块然后识别出图像块中央的字符。为了简化操作,我们会将这些图像处理成灰度图像而不是彩色图像,实际上,使用彩色图像对这个具体问题而言帮助不大。
给定这个图像块(上图1蓝色标注),希望机器能识别出 T \rm T T,对于这个图像块(上图2绿色标注),希望能识别出 S \rm S S,对于这个图像块(上图3紫色标注),我们希望能识别出 I \rm I I,等等。这里所有例子都是真实图像,我们怎样才能得到一个更大的训练集呢?现代计算机通常有一个庞大的字体库,假如我们使用一个文字处理软件,不同的文字处理软件可能有所有这些字体,并且还有更多内置字体。事实上,如果我们去浏览不同网站,网上还有庞大的免费字体库,我们能下载许多不同类型的字体,有上百种甚至是上千种不同的字体。
所以,假如我们想要更多的训练样本,一个方法是用不同的字体生成字符(take characters from different fonts),然后将其粘贴到任意不同的背景中,比如说,我们可以将这个字母 C \rm C C 粘贴在任意背景中(上图红色标注),操作完成后,我们现在就有了一个字符 C \rm C C 的图像训练样本,在完成一些相同的操作之后,要想合成能以假乱真的数据的确需要花一番功夫,但做完这些工作之后,我们就会得到像这样的人造训练集(下图右),里面的每一个图像,实际上都是一个合成图像,它是用一个字体,可能是从网上下载的字体,我们将这种字体的一个字符图像或是多个字符图像粘贴到另一个任意背景图中,然后可以应用一点模糊算子(blurring operations)或者仿射变换(affine distortions),仿射的意思是进行等分缩放和一些旋转操作。完成这些操作后,我们会得到一个人工合成训练集。
这要花费一些功夫,为了使合成的数据更逼真,我们需要在操作中花些心思。如果我们在创造人工数据时做的不好,那使用效果就不好。我们看一下上图右侧这些合成数据,它实际上与真实数据非常相似,那么使用合成的数据,我们实际上能为我们的人工训练合成提供无限的训练数据样本。因此,如果我们使用这种合成数据,我们就会有无限的标签数据来为字符识别问题生成一个监督学习算法。
在这个人工数据合成的例子中,我们基本上是从零开始生成新数据的,也就是从零开始产生新的图像。
我们拿一个真实的样本,可能来自一张真的图片,然后生成一些其它的数据以扩充训练集。这是一张字符 A \rm A A 的图像(上图左),它取自一张真实图像,而不是合成图像,我们在上面覆盖了网格线,只是为了便于说明,实际上不会有网格线。接下来要做的是,对这个字母,这张图进行人工拉伸(artificial warpings),或者说人工扭曲(artificial distortions),这样就可以将这个图 A \rm A A 变成 16 16 16 个新的样本。采用这种办法,我们就能将一个小的标签训练集扩充为一个更大的训练集。同样的,这个应用中,为了得到这种效果,确实要花些心思,并且需要深入理解来解决哪些扭曲是合理的,哪些操作能够用来扩充以及增加我们的训练集。对于字符识别这一特定例子引入这些拉伸看起来是个很自然的选择,但是对于其他机器学习应用来说,可能其它类型的失真将会更合理,我们举一个不同领域的例子,即语音识别(speech recognition),对语音识别而言,假定我们有一些音频片段,然后我们想从中学习来识别语音片段中出现的单词。
⊲ ) ) O r i g i n a l a u d i o ⊲ ) ) A u d i o o n b a d c e l l p h o n e c o n n e c t i o n ⊲ ) ) N o i s y b a c k g r o u n d : C r o w d ⊲ ) ) N o i s y b a c k g r o u n d : M a c h i n e r y \begin{aligned} &\lhd)\big)\ \rm Original\ \ audio\\ &\lhd)\big)\ \rm Audio\ \ on\ \ bad\ \ cellphone\ \ connection\\ &\lhd)\big)\ \rm Noisy\ \ background:\ \ Crowd\\ &\lhd)\big)\ \rm Noisy\ \ background:\ \ Machinery\\ \end{aligned} ⊲)) Original audio⊲)) Audio on bad cellphone connection⊲)) Noisy background: Crowd⊲)) Noisy background: Machinery
假定有一个带标签的训练样本,它是某个人说的一些词,我们想尝试应用一个学习算法来识别出那个人说的单词,那么,我们该如何扩充数据集呢?我们能做的是引入额外的语音失真到数据集中,这里我们加入背景音,来模拟手机通话信号不好的情况,我们会听到蜂鸣声,它实际上是音轨的一部分,而不是扬声器的问题,这个声音可以作为另一个有用的训练样本;另一个例子则是嘈杂的背景音,背景音中有汽车经过、行人走过的的声音。
我们拿原来的 “ 干净 ” 的音频自动合成这些其他的训练样本,从一个训练样本生成四种不同的训练样本。因此,仅通过一个标签样本,只需要花功夫收集一个标签样本,通过人工添加失真,引入不同的背景声音,我们现在很容易将一个样例扩充为更多的样本,即自动化添加这些不同的背景声音到 “ 干净 ” 的音频中。
Component | Accuracy |
---|---|
Overall system | 72% |
Text detection | 89% |
Character segmentation | 90% |
Character recognition | 100% |
假如我们第一步要做的是图像预处理,假如就用这张图片(下图1),现在我们想要把背景去掉,那么经过预处理背景就被去掉了(下图2)。下一步我们希望检测出人脸的位置,这通常通过一个学习算法来实现,我们会运行一个滑动窗分类器,在人脸上画一个框(下图3)。
在检测到脸部以后,如果我们想要识别出这个人,那么眼睛是一个很重要的线索,事实上,要辨认出你的朋友你通常会看眼睛,这是个比较重要的线索,所以我们需要运行另一个分类器来检测人的眼睛,分割出眼睛,这样就提供了识别出一个人的很重要的特征,然后继续找出脸上其他重要的部位,比如分割出鼻子,分割出嘴巴(上图4)。这样找出了眼睛、鼻子、嘴巴,所有这些都是非常有用的特征,可以被输入给某个逻辑回归的分类器,然后这个分类器的任务就是给出最终的标签,辨识出这个人是谁。这是一个稍微复杂一些的流水线,如果你真的想识别出人的话,可能实际的工作流比这个还要复杂,但这是一个很好的例子用来弄清楚上限分析。
Component | Accuracy |
---|---|
Overall system | 85% |
Preprocess (remove background) | 85.1% |
Face detection | 91% |
Eyes segmentation | 95% |
Nose segmentation | 96% |
Mouth segmentation | 97% |
Logistic regression | 100% |