[译]OpenCV Text Detection (EAST text detector)

by Adrian Rosebrock on August 20, 2018 in Deep Learning, Optical Character Recognition (OCR), Tutorials
点击这里下载这篇文章的源代码python

图片描述

在本教程中,您将学习如何使用EAST文本检测器使用OpenCV检测天然场景图像中的文本。
OpenCV的EAST文本检测器是一种基于新颖架构和训练模式的深度学习模型。它可以(1)在720p图像上以13 FPS接近实时运行,而且(2)得到最早进的文本检测精度。
在本教程的其他部分,您将学习如何使用OpenCV的EAST检测器自动检测图像和视频流中的文本。算法

在本教程中,您将学习如何使用EAST文本检测器使用OpenCV检测图像中的文本。
EAST文本检测器要求咱们在咱们的系统上运行OpenCV 3.4.2或OpenCV 4 - 若是您尚未安装OpenCV 3.4.2或更高版本,请参阅个人OpenCV安装指南并按照各自的操做系统进行操做。
在今天的教程的第一部分中,我将讨论为何在天然场景图像中检测文本会如此具备挑战性。
从那里我将简要讨论EAST文本检测器,咱们为何使用它,以及使算法如此新颖的缘由 - 我还将包含原始论文的连接,以便您能够阅读详细信息,若是您如此倾向。
最后,我将提供个人Python + OpenCV文本检测实现,以便您能够开始在本身的应用程序中应用文本检测。安全

为何天然场景文本检测如此具备挑战性网络

clipboard.png
图1:天然场景图像的示例,其中文本检测因为光照条件,图像质量和非平面物体而具备挑战性(Mancas-Thillou和Gosselin的图1)。架构

在受约束的受控环境中检测文本一般能够经过使用基于启发式的方法来完成,例如利用梯度信息或者文本一般被分组成段落而且字符出如今直线上的事实。在我以前关于检测护照图像中的机器可读区域的博客文章中能够看到这种基于启发式的文本检测器的示例。
天然场景文本检测虽然不一样 - 并且更具挑战性。
因为廉价数码相机的普及,更不用说几乎每部智能手机如今都有摄像头这一事实,咱们须要高度关注拍摄图像的条件 - 此外,咱们能作什么和不能作什么假设。我已经包含了Celine Mancas-Thillou和Bernard Gosselin在2017年优秀论文“天然场景文本理解”中描述的天然场景文本检测挑战的总结版本:
.图像/传感器噪声:手持式摄像机的传感器噪声一般高于传统扫描仪的噪声。此外,低价相机一般会插入原始传感器的像素以产生真实的颜色。
.视角:天然场景文本天然能够具备与文本不平行的视角,使文本更难识别。
.模糊:不受控制的环境每每会模糊,特别是若是最终用户使用的智能手机没有某种形式的稳定性。
.照明条件:咱们没法对天然场景图像中的照明条件作出任何假设。它可能接近黑暗,相机上的闪光灯可能会亮起,或者太阳可能会发出明亮的光线,使整个图像饱和。
.分辨率:并不是全部摄像机都是相同的 - 咱们可能在处理分辨率低于标准的相机。
.非纸质对象:大多数(但不是所有)纸张都不是反光的(至少在您尝试扫描的纸张环境中)。天然场景中的文字多是反光的,包括徽标,标志等。
.非平面物体:考虑当您将文本环绕在瓶子周围时会发生什么 - 表面上的文本变得扭曲和变形。虽然人类仍然能够轻松地“检测”并阅读文本,但咱们的算法会很困难。咱们须要可以处理这样的用例。
.未知布局:咱们不能使用任何先验信息来为咱们的算法提供关于文本所在位置的“线索”。app

正如咱们将要了解的那样,OpenCV的EAST文本检测器实现很是强大,即便文本模糊,反射或部分模糊,也可以对文本进行本地化:框架

clipboard.png
图2:OpenCV的EAST场景文本检测器即便在模糊和模糊的图像中也能检测到。ide

EAST深度学习文本检测器函数

clipboard.png
图3:EAST文本检测全卷积网络的结构(Zhou等人的图3)。oop

随着OpenCV 3.4.2和OpenCV 4的发布,咱们如今可使用一种名为EAST的基于深度学习的文本检测器,它基于Zhou等人的2017年论文“EAST:一种高效精确的场景文本检测器”。
咱们将算法称为“EAST”,由于它是:高效且准确的场景文本检测管道。
据做者说,EAST管道可以在720p图像上以任意方向预测文本的单词和行,而且可以以13 FPS运行。
也许最重要的是,因为深度学习模型是端到端的,所以能够回避其余文本检测器一般应用的计算上昂贵的子算法,包括候选聚合和字分区。
为了构建和训练这样一种深度学习模型,EAST方法采用了新颖,精心设计的损失函数。
有关EAST的更多详细信息,包括架构设计和培训方法,请务必参考做者的出版物。

项目结构

首先,请访问“下载”部分,确保将源代码+图像抓取到今天的帖子。从那里,只需使用tree terminal命令查看项目结构:

$ tree --dirsfirst
.
├── images
│   ├── car_wash.png
│   ├── lebron_james.jpg
│   └── sign.jpg
├── frozen_east_text_detection.pb
├── text_detection.py
└── text_detection_video.py

1 directory, 6 files

请注意,我在images /目录中提供了三张示例图片。您可能但愿添加本身使用智能手机收集的图像或在线查找的图像。
咱们今天将审查两个.py文件:
text_detection.py:检测静态图像中的文本。
text_detection_video.py:经过网络摄像头或输入视频文件检测文本。

这两个脚本都使用了序列化的EAST模型(frozen_east_text_detection.pb),以便在“下载”中提供。

实施说明

我今天包含的文本检测实现基于OpenCV的官方C ++示例;可是,我必须认可在将其转换为Python时遇到了一些麻烦。
首先,Python中没有Point2f和RotatedRect函数,所以,我没法100%模仿C ++实现。 C ++实现能够生成旋转的边界框,但不幸的是,我今天与你分享的那个不能。
其次,NMSBoxes函数不返回Python绑定的任何值(至少对于个人OpenCV 4预发布安装),最终致使OpenCV抛出错误。 NMSBoxes函数能够在OpenCV 3.4.2中工做,但我没法对其进行详尽的测试。
我解决了这个问题,我在imutils中使用我本身的非最大值抑制实现,但一样,我不相信这两个是100%可互换的,由于看起来NMSBoxes接受其余参数。
鉴于这一切,我尽力使用个人工做功能和资源为您提供最好的OpenCV文本检测实现。若是您对方法有任何改进,请随时在下面的评论中分享。

使用OpenCV实现咱们的文本检测器

在咱们开始以前,我想指出您至少须要在系统上安装OpenCV 3.4.2(或OpenCV 4)才能使用OpenCV的EAST文本检测器,所以若是您还没有安装OpenCV 3.4.2或更高版本在您的系统上,请参阅个人OpenCV安装指南。

接下来,确保您的系统上还安装/升级了imutils:
pip install --upgrade imutils
此时您的系统已配置好,所以打开text_detection.py并插入如下代码:

clipboard.png

首先,咱们在第2-6行导入咱们所需的包和模块。值得注意的是,咱们从imutils.object_detection导入NumPy,OpenCV和个人non_max_suppression实现。

而后咱们继续解析第9-20行的五个命令行参数:
--image:输入图像的路径。
--east:EAST场景文本检测器模型文件路径。
--min-confidence:肯定文本的几率阈值。可选,默认值= 0.5。
--width:调整后的图像宽度 - 必须是32的倍数。可选,默认值= 320。
--height:调整后的图像高度 - 必须是32的倍数。可选,默认值= 320。

重要提示:EAST文本要求输入图像尺寸为32的倍数,所以若是您选择调整--width和--height值,请确保它们是32的倍数!

从那里,让咱们加载咱们的图像并调整它的大小:

clipboard.png

在第23和24行,咱们加载并复制输入图像。

从那里,第30行和第31行肯定原始图像尺寸与新图像尺寸的比率(基于为--width和--height提供的命令行参数)。

而后咱们调整图像大小,忽略纵横比(第34行)。

为了使用OpenCV和EAST深度学习模型执行文本检测,咱们须要提取两层的输出特征映射:

clipboard.png

咱们在40-42行构建一个layerNames列表:
第一层是咱们的输出sigmoid激活,它给出了包含文本或不包含文本的区域的几率。
第二层是表示图像“几何”的输出要素图 - 咱们将可以使用此几何来导出输入图像中文本的边界框坐标

让咱们加载OpenCV的EAST文本检测器:

clipboard.png

咱们使用cv2.dnn.readNet将神经网络加载到内存中,方法是将路径传递给EAST检测器(包含在咱们的命令行args字典中)做为第46行的参数。

而后咱们经过将其转换为第50行和第51行的blob来准备咱们的图像。要了解有关此步骤的更多信息,请参阅深度学习:OpenCV的blobFromImage如何工做。

要预测文本,咱们能够简单地将blob设置为输入并调用net.forward(第53和54行)。这些行被抓取时间戳包围,以便咱们能够在第58行打印通过的时间。

经过将layerNames做为参数提供给net.forward,咱们正在指示OpenCV返回咱们感兴趣的两个特征映射:
输出几何图用于导出输入图像中文本的边界框坐标
相似地,分数图包含包含文本的给定区域的几率

咱们须要逐个遍历每一个值:

clipboard.png

咱们首先抓住得份量的维度(第63行),而后初始化两个列表:
rects:存储文本区域的边界框(x,y) - 坐标
置信度:存储与rects中每一个边界框关联的几率

咱们稍后将对这些区域应用非最大值抑制。

在第68行开始循环。

第72-77行提取当前行的分数和几何数据y。

接下来,咱们遍历当前所选行的每一个列索引:

clipboard.png

对于每一行,咱们开始循环第80行的列。

咱们须要经过忽略不具备足够高几率的区域来过滤掉弱文本检测(第82和83行)。

当文本经过网络时,EAST文本检测器天然地减少了体积大小 - 咱们的体积大小实际上比输入图像小4倍,因此咱们乘以4使坐标回到原始图像的方向。

我已经介绍了如何在第91-93行提取角度数据;可是,正如我在上一节中所提到的,我没法像在C ++实现中那样构建一个旋转的边界框 - 若是你想要处理任务,从第91行的角度开始将是你的第一个步。

从那里,第97-105行导出文本区域的边界框坐标。

而后,咱们分别更新咱们的rects和confidences列表(第109和110行)。

咱们差很少完成了!

最后一步是将非最大值抑制应用于咱们的边界框以抑制弱重叠边界框,而后显示结果文本预测:

clipboard.png

正如我在上一节中提到的,我没法在个人OpenCV 4安装(cv2.dnn.NMSBoxes)中使用非最大值抑制,由于Python绑定没有返回值,最终致使OpenCV错误输出。我没法彻底在OpenCV 3.4.2中进行测试,所以它能够在v3.4.2中运行。

相反,我使用了imutils包中提供的非最大值抑制实现(第114行)。结果仍然很好;可是,我没法将输出与NMSBoxes函数进行比较,看看它们是否相同。

第117-126行环绕咱们的边界框,将坐标缩放回原始图像尺寸,并将输出绘制到咱们的原始图像。显示原始图像,直到按下一个键(第129和130行)。

做为最后的实现说明,我想提一下,咱们的两个嵌套for循环用于循环第68-110行的分数和几何体积,这将是一个很好的例子,你能够利用Cython来大大加速你的管道。我已经展现了Cython在Fast中的强大功能,使用OpenCV和Python优化了'for'像素循环。
OpenCV文本检测结果

你准备好对图像应用文本检测了吗?

首先抓住此博客文章的“下载”并解压缩文件。

从那里,您能够在终端中执行如下命令(记下两个命令行参数):

$ python text_detection.py --image images/lebron_james.jpg \
    --east frozen_east_text_detection.pb
[INFO] loading EAST text detector...
[INFO] text detection took 0.142082 seconds

您的结果应相似于如下图像:

clipboard.png
图4:着名的篮球运动员,Lebron James的球衣文字经过OpenCV和EAST文本检测成功识别。

勒布朗詹姆斯肯定了三个文本区域。

如今让咱们尝试检测商业标志的文字:

$ python text_detection.py --image images/car_wash.png \
    --east frozen_east_text_detection.pb
[INFO] loading EAST text detector...
[INFO] text detection took 0.142295 seconds

clipboard.png
图5:在洗车站的这个天然场景中使用EAST和Python以及OpenCV能够轻松识别文本。

最后,咱们将尝试一个路标:

$ python text_detection.py --image images/sign.jpg \
    --east frozen_east_text_detection.pb
[INFO] loading EAST text detector...
[INFO] text detection took 0.141675 seconds

clipboard.png
图6:使用Python + OpenCV进行场景文本检测,EAST文本检测器成功检测到此西班牙语中止标志上的文本。

此场景包含西班牙停车标志。 OpenCV和EAST正确检测到“ALTO”这个词。

正如您所知,EAST很是准确且相对较快,每张图像的平均时间约为0.14秒。

使用OpenCV在视频中进行文本检测

如今咱们已经看到了如何检测图像中的文本,让咱们继续使用OpenCV检测视频中的文本。

这个解释很是简短;有关详细信息,请参阅上一节。

打开text_detection_video.py并插入如下代码:

# import the necessary packages
from imutils.video import VideoStream
from imutils.video import FPS
from imutils.object_detection import non_max_suppression
import numpy as np
import argparse
import imutils
import time
import cv2

咱们首先导入咱们的包。咱们将使用VideoStream访问网络摄像头和FPS以对此脚本的每秒帧数进行基准测试。其余全部内容与上一节中的相同。

为方便起见,让咱们定义一个新函数来解码咱们的预测函数 - 它将被重用于每一个帧并使咱们的循环更清晰

def decode_predictions(scores, geometry):
    # grab the number of rows and columns from the scores volume, then
    # initialize our set of bounding box rectangles and corresponding
    # confidence scores
    (numRows, numCols) = scores.shape[2:4]
    rects = []
    confidences = []

    # loop over the number of rows
    for y in range(0, numRows):
        # extract the scores (probabilities), followed by the
        # geometrical data used to derive potential bounding box
        # coordinates that surround text
        scoresData = scores[0, 0, y]
        xData0 = geometry[0, 0, y]
        xData1 = geometry[0, 1, y]
        xData2 = geometry[0, 2, y]
        xData3 = geometry[0, 3, y]
        anglesData = geometry[0, 4, y]

        # loop over the number of columns
        for x in range(0, numCols):
            # if our score does not have sufficient probability,
            # ignore it
            if scoresData[x] < args["min_confidence"]:
                continue

            # compute the offset factor as our resulting feature
            # maps will be 4x smaller than the input image
            (offsetX, offsetY) = (x * 4.0, y * 4.0)

            # extract the rotation angle for the prediction and
            # then compute the sin and cosine
            angle = anglesData[x]
            cos = np.cos(angle)
            sin = np.sin(angle)

            # use the geometry volume to derive the width and height
            # of the bounding box
            h = xData0[x] + xData2[x]
            w = xData1[x] + xData3[x]

            # compute both the starting and ending (x, y)-coordinates
            # for the text prediction bounding box
            endX = int(offsetX + (cos * xData1[x]) + (sin * xData2[x]))
            endY = int(offsetY - (sin * xData1[x]) + (cos * xData2[x]))
            startX = int(endX - w)
            startY = int(endY - h)

            # add the bounding box coordinates and probability score
            # to our respective lists
            rects.append((startX, startY, endX, endY))
            confidences.append(scoresData[x])

    # return a tuple of the bounding boxes and associated confidences
    return (rects, confidences)

咱们定义了decode_predictions函数。此函数用于提取:
文本区域的边界框坐标
以及文本区域检测的几率

这个专用函数将使代码在之后的脚本中更易于阅读和管理。

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-east", "--east", type=str, required=True,
    help="path to input EAST text detector")
ap.add_argument("-v", "--video", type=str,
    help="path to optinal input video file")
ap.add_argument("-c", "--min-confidence", type=float, default=0.5,
    help="minimum probability required to inspect a region")
ap.add_argument("-w", "--width", type=int, default=320,
    help="resized image width (should be multiple of 32)")
ap.add_argument("-e", "--height", type=int, default=320,
    help="resized image height (should be multiple of 32)")
args = vars(ap.parse_args())

咱们的命令行参数解析:
--east:EAST场景文本检测器模型文件路径。
--video:输入视频的路径。可选 - 若是提供了视频路径,则不会使用网络摄像头。
--min-confidence:肯定文本的几率阈值。可选,默认值= 0.5。
--width:调整后的图像宽度(必须是32的倍数)。可选,默认值= 320。
--height:调整后的图像高度(必须是32的倍数)。可选,默认值= 320。

上一节中仅使用图像的脚本(就命令行参数而言)的主要变化是我用--video替换了--image参数。

重要提示:EAST文本要求输入图像尺寸为32的倍数,所以若是您选择调整--width和--height值,请确保它们是32的倍数!

接下来,咱们将执行模仿前一个脚本的重要初始化:

clipboard.png

第84-86行的高度/宽度和比率初始化将容许咱们稍后正确地缩放咱们的边界框。

定义了输出层名称,咱们在第91-97行加载了预训练的EAST文本检测器。

如下块设置咱们的视频流和每秒帧数计数器:

clipboard.png

咱们的视频流设置为:
网络摄像头(100-103行)
或视频文件(第106-107行)

从那里咱们初始化咱们在第110行的每秒帧数,并开始循环传入帧:

clipboard.png

咱们开始在113行​​的视频/网络摄像头帧上循环。

咱们的框架调整大小,保持纵横比(第124行)。从那里,咱们抓住尺寸并计算比例比(第129-132行)。而后咱们再次调整框架的大小(必须是32的倍数),此次忽略纵横比,由于咱们已经存储了安全保持的比率(第135行)。

预测和绘图文本区域边界框发生在如下行:

clipboard.png

在这个块中咱们:
使用EAST经过建立blob并将其传递经过网络来检测文本区域(第139-142行)
解码预测并应用NMS(第146和147行)。咱们使用此脚本中先前定义的decode_predictions函数和个人imutils non_max_suppression便利函数。
环绕边界框并在框架上绘制它们(第150-159行)。这涉及经过先前收集的比率来缩放框。

从那里咱们将关闭帧处理循环以及脚本自己:

clipboard.png

咱们在循环的每次迭代中更新咱们的fps计数器(第162行),以便在咱们突破循环时计算并显示计时(第173-175行)。

咱们在165行显示EAST文本检测的输出并处理按键(第166-170行)。若是按“q”进行“退出”,咱们就会跳出循环并继续清理并释放指针。

视频文本检测结果

要使用OpenCV将文本检测应用于视频,请务必使用此博客文章的“下载”部分。

从那里,打开一个终端并执行如下命令(这将启动你的网络摄像头,由于咱们没有经过命令行参数提供--video):

$ python text_detection_video.py --east frozen_east_text_detection.pb 
[INFO] loading EAST text detector...
[INFO] starting video stream...
[INFO] elasped time: 59.76
[INFO] approx. FPS: 8.85

图片描述

咱们的OpenCV文本检测视频脚本可实现7-9 FPS。

这个结果并不像做者报道的那么快(13 FPS);可是,咱们使用的是Python而不是C ++。经过使用Cython优化for循环,咱们应该可以提升文本检测管道的速度。

摘要

在今天的博客文章中,咱们学习了如何使用OpenCV的新EAST文本检测器来自动检测天然场景图像中是否存在文本。

文本检测器不只准确,并且可以在720p图像上以近似实时的速度运行,大约13 FPS。

为了提供OpenCV的EAST文本检测器的实现,我须要转换OpenCV的C ++示例;然而,我遇到了许多挑战,例如:
没法使用OpenCV的NMSBox进行非最大值抑制,而是必须使用imutils的实现。
因为缺乏RotatedRect的Python绑定,没法计算真正的旋转边界框。

我试图让个人实现尽量接近OpenCV,但请记住,个人版本与C ++版本没有100%彻底相同,而且可能会有一两个小问题须要随着时间的推移而解决。

不管如何,我但愿你喜欢今天的OpenCV文本检测教程!

相关文章
相关标签/搜索