文本检测识别算法

[TOC]

CTPN(Connectionist Text Proposal Network)

idea

  • 文本检测和一般目标检测的不同——文本线是一个sequence(字符、字符的一部分、多字符组成的一个sequence),而不是一般目标检测中只有一个独立的目标。这既是优势,也是难点。优势体现在同一文本线上不同字符可以互相利用上下文,可以用sequence的方法比如RNN来表示。难点体现在要检测出一个完整的文本线,同一文本线上不同字符可能差异大,距离远,要作为一个整体检测出来难度比单个目标更大——因此,作者认为预测文本的竖直位置(文本bounding box的上下边界)比水平位置(文本bounding box的左右边界)更容易。

  • Top-down(先检测文本区域,再找出文本线)的文本检测方法比传统的bottom-up的检测方法(先检测字符,再串成文本线)更好。自底向上的方法的缺点在于(这点在作者的另一篇文章中说的更清楚),总结起来就是没有考虑上下文,不够鲁棒,系统需要太多子模块,太复杂且误差逐步积累,性能受限。

  • RNN和CNN的无缝结合可以提高检测精度。CNN用来提取深度特征,RNN用来序列的特征识别(2类),二者无缝结合,用在检测上性能更好。

pipeline

image

  1. VGG16的前5个conv stage(conv5_3)作为base net得到 feature map(W H C)
  2. 在Conv5的feature map的每个位置上取3 3 C的窗口的特征,这些特征将用于预测该位置k个anchor(anchor的定义和Faster RCNN类似)对应的类别信息,位置信息。这个特征向量将用来预测和10个anchor之间的偏移距离,也就是说每一个窗口中心都会预测出10个text propsoal。
  3. 将每一行的所有窗口对应的33C的特征(W33C)输入到RNN(BLSTM)中,得到W256的输出
  4. 将RNN的W*256输入到512维的fc层
  5. fc层特征输入到三个分类或者回归层中。第二个2k scores 表示的是k个anchor的类别信息(是字符或不是字符)。第一个2k vertical coordinate和第三个k side-refinement是用来回归k个anchor的位置信息。2k vertical coordinate表示的是bounding box的高度和中心的y轴坐标(可以决定上下边界),k个side-refinement表示的bounding box的水平平移量。这边注意,只用了3个参数表示回归的bounding box,因为这里默认了每个anchor的width是16,且不再变化(VGG16的conv5的stride是16)。回归出来的box如Fig.1中那些红色的细长矩形,它们的宽度是一定的。
  6. 用简单的文本线构造算法,把分类得到的文字的proposal(图Fig.1(b)中的细长的矩形)合并成文本线

细节

  • conv5的featuremap作为输入入,宽度恰好被固定为16个像素。只用来预测纵轴y即可。

image

c anchor中心,h anchor高度,a 是预测,*是实际,h是提议的高度

  • score阈值设置:0.7 (+NMS)
  • Recurrent Connectionist Text Proposals
    • RNN类型:BLSTM(双向LSTM),每个LSTM有128个隐含层
    • RNN输入:每个滑动窗口的33C的特征(可以拉成一列),同一行的窗口的特征形成一个序列
    • RNN输出:每个窗口对应256维特征
    • 使用RNN和不适用RNN的效果对比,CTPN是本文的方法(Connectionist Text Proposal Network)

总结

这篇文章的方法最大亮点在于把RNN引入检测问题(以前一般做识别)。文本检测,先用CNN得到深度特征,然后用固定宽度的anchor来检测text proposal(文本线的一部分),并把同一行anchor对应的特征串成序列,输入到RNN中,最后用全连接层来分类或回归,并将正确的text proposal进行合并成文本线。这种把RNN和CNN无缝结合的方法提高了检测精度。

翻译原文

参考——1

参考——2

EAST: An Efficient and Accurate Scene Text Detector

旷世科技 CVPR2017

image

1.分析目前存在的文本检测方法总结

  1. a– Reading Text in the Wild with Convolutional Neural Networks (15年vgg实验室提出,只能检测、识别水平文字)

    整个方法分为两部分,1.检测,使用Region Proposal mechanism检测数文字区域,然后使用Proposal Filtering(使用的是random forest方法)过滤文字候选框,最后进行一些合并调整得到Word boxes,这部分由于Bounding Box Regression不能完全覆盖文字,导致识别错误,所以又搞了个CNN网络来调整regression framework。2.识别,使用CNN一次识别出整个单词,与以往的单词分割识别再组合不同,这部分数据是人工生成的[方法1]

    参考文章
    论文

  2. b– Multi-Oriented Text Detection with Fully Convolutional Networks (2016CVPR 白翔大佬,检测多方向文字)

    具体方法是,将输入图片经过几层卷积得到salient map,然后使用MSER提取候选文字区域,接着候选字符提取出来,确定整个候选字符的方向,最后生成候选框

    参考文章
    论文

  3. c – Scene Text Detection via Holistic, Multi-Channel Prediction (arXiv2016 白翔大佬在Face++的)

    这个主要方法是从原图中获取三个mask,分别是文本行mask,字符mask和方向mask,然后使用这三个mask获取文本框。文本行mask数据集有,那字符和方向的mask是怎么得到的呢,通过swt得到字符mask,然后获取方向的mask.

    有三个mask怎么得到文本框的呢,可以是文本行mask得到一个文本框,使用字符框得到多个框再使用德劳内三角化,最后得到文本框。

    参考文章-1
    参考文章-2
    论文

  4. d – Detecting Text in Natural Image with Connectionist Text Proposal Network (Weilin Huang——ECCV2016)

    这个就是大名鼎鼎的CTPN啦

2.Pipeline 网络结构

image

分为三部分:feature extractor\feature-merging\output layer

  1. Feature extractor 特征提取

    使用PVNet提取图片特征,分别抽出1/4、1/8、1/16、1/32大小的feature map

  2. Feature merging 特征合并

    将上面提取的特征上采样合并,最后得到32channel的featuare

  3. Output layer 输出层

    分为两部分:score map和 RBOX or QUAD

    score map 是使用1*1的卷积核获取的。RBOX是带角度的Box,这个分为4个geomatry map和1个rotation angle。QUAD是四个坐标点,xy两轴,所以是8个。

3.Label generation

image

当输出4个Geomatry map和一个rototion map时,label怎么生成的呢。看上图,(a)中黄色虚线框是人工标注,绿色实现框是缩小0.3后的Label,文章说这样可以避免人工标注错误带来的误差;(b)就是score map label,白色表示文本区域,黑色表示背景;(c) 生成RBOX几何映射;(d)每个像素到矩形边界的距离有4个通道;(e)旋转角度.

4. Loss Function

$L = L _ { \mathrm { s } } + \lambda _ { \mathrm { g } } L _ { \mathrm { g } }$

Ls和Lg分别代表scoreh额geomatry的loss,λg代表权重,文章设为1

$L _ { \mathrm {s}}= - \beta \mathbf { Y } ^{}\log \hat { \mathbf { Y } } - ( 1 - \beta ) \left( 1 - \mathbf { Y } ^ { } \right) \log ( 1 - \hat { \mathbf { Y } } )$

Ls使用的是交叉熵

在Geomatry生成使用RBox和Quad时用不同的Loss function

RBox 的loss分为AABB和R两部分,Box AABB的loss是iou

$L _ { \mathrm { AABB } } = - \log \operatorname { IoU } \left( \hat { \mathbf { R } } , \mathbf { R } ^ { } \right) = - \log \frac { \left| \hat { \mathbf { R } } \cap \mathbf { R } ^ { } \right| } { \left| \hat { \mathbf { R } } \cup \mathbf { R } ^ { * } \right| }$

但是这里的iou是加了权重的,是加到各个边的距离的权重,角度loss使用cos 计算

$L _ { \theta } \left( \hat { \theta } , \theta ^ { } \right) = 1 - \cos \left( \hat { \theta } - \theta ^ { } \right)$

下面是RBox loss的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def loss(y_true_cls, y_pred_cls,
y_true_geo, y_pred_geo,
training_mask):
'''
define the loss used for training, contraning two part,
the first part we use dice loss instead of weighted logloss,
the second part is the iou loss defined in the paper
:param y_true_cls: ground truth of text
:param y_pred_cls: prediction os text
:param y_true_geo: ground truth of geometry
:param y_pred_geo: prediction of geometry
:param training_mask: mask used in training, to ignore some text annotated by ###
:return:
'''
classification_loss = dice_coefficient(y_true_cls, y_pred_cls, training_mask)
# scale classification loss to match the iou loss part
classification_loss *= 0.01

# d1 -> top, d2->right, d3->bottom, d4->left
d1_gt, d2_gt, d3_gt, d4_gt, theta_gt = tf.split(value=y_true_geo, num_or_size_splits=5, axis=3)
d1_pred, d2_pred, d3_pred, d4_pred, theta_pred = tf.split(value=y_pred_geo, num_or_size_splits=5, axis=3)
area_gt = (d1_gt + d3_gt) * (d2_gt + d4_gt)
area_pred = (d1_pred + d3_pred) * (d2_pred + d4_pred)
w_union = tf.minimum(d2_gt, d2_pred) + tf.minimum(d4_gt, d4_pred)
h_union = tf.minimum(d1_gt, d1_pred) + tf.minimum(d3_gt, d3_pred)
area_intersect = w_union * h_union
area_union = area_gt + area_pred - area_intersect
L_AABB = -tf.log((area_intersect + 1.0)/(area_union + 1.0))
L_theta = 1 - tf.cos(theta_pred - theta_gt)
tf.summary.scalar('geometry_AABB', tf.reduce_mean(L_AABB * y_true_cls * training_mask))
tf.summary.scalar('geometry_theta', tf.reduce_mean(L_theta * y_true_cls * training_mask))
L_g = L_AABB + 20 * L_theta

return tf.reduce_mean(L_g * y_true_cls * training_mask) + classification_loss

Quad loss, ⚆_⚆ 没看懂怎么做的,也没有代码,这里仅贴个公式吧。

$L _ { \mathrm { g } } = L _ { \mathrm { QUAD } } \left( \hat { \mathbf { Q } } , \mathbf { Q } ^ { } \right) = \min _ { \mathbf { Q } \in P _ { Q ^ { } } } \sum _ { c _ { i } \in \mathbb { C } _ { \mathbf { Q } } } \frac { \operatorname { smoothed } _ { L 1 } \left( c _ { i } - \tilde { c } _ { i } \right) } { 8 \times N _ { \mathbf { Q } ^ { * } } }$

5. Locality-Aware NMS

locality_aware_nms在标准nms的基础上加了weighted_merge,所谓weighted_merge就是将2个IOU高于某个threshold的输出框,进行基于得分的合并。合并后的输出框的坐标数值介于2个合并的输入框之间,感觉这样操作可以将所有回归出的框的坐标信息都利用起来,有助于减少位置误差,而不是像传统的nms一样,直接取分数最高的那个。

参考文章_1

参考文章_2

参考文章_3

参考文章_4

AdvancedEAST

Seglink (Detecting Oriented Text in Natural Images by Linking Segments)

论文

代码

1. idea

  • 提出了文本行检测的两个基本组成元素:==segment==和==link==
  • 提出了基于SSD的改进版网络结构(全卷积网络结果)同时预测不同尺度的segments和link
  • 提出了两种link类型: 层内连接(within-layer link)和跨层连接(cross-layer link)
  • 可以处理多方向和任意长度的文本
  • Pipeline
  • 整个实现过程包括两部分:首先检测segments,links,然后使用融合算法得到最终文本行.具体步骤如下:

2. Pipeline

主干网络是沿用了SSD网络结构,并修改修改了最后的Pooling层,将其改为卷积层.

  • 首先用VGG16作为base net,并将VGG16的最后两个全连接层改成卷积层.
  • 接着增加一些额外的卷积层,用于提取更深的特征,最后的修改SSD的Pooling层,将其改为卷积层提取不同层的feature map,文中提取了conv4_3, conv7, conv8_2, conv9_2, conv10_2, conv11.这里其实操作还是和SSD网络一样,对不同层的featuremap使用3*3的卷积层产生最终的输出(包括segment和link),不同特征层输出的维度是不一样的,因为除了conv4_3层外,其它层存在跨层的link.这里segment是text的带方向bbox信息(它可能是个单词,也可能是几个字符,总之是文本行的部分),link是不同bbox的连接信息(文章将其也增加到网络中自动学习).
  • 然后通过融合规则,将segment的box信息和link信息进行融合,得到最终的文本行.

PixelLink

1. Abstract

基于语义分割的文本检测会有文本彼此接近导致它们很难分离.这篇文章使用将同一实例像素连接在一起进行分割。

以前的方法都至少包含两中分类:

  1. 文本\非文本分类(SegLink\EAST\TextBoxes)
  2. 位置回归 (SegLink\CTPN\EAST)

PixelLink受Seglink启发,分别预测文本、非文本和相邻8个像素的连接.

2. Network Architecture

image

PixelLink的架构。训练CNN模型以执行两种基于像素的预测:文本/非文本预测和链接预测。经过阈值处理后,通过正向链接将正像素连接在一起,实现实例分割。然后应用minAreaRect直接从分割结果中提取边界框。使用后置滤波可以有效地消除噪音预测。为了更好地说明输入样本。虚线框中的八个热图代表八个方向上的链接预测。虽然有些词在文本/非文本预测中难以分离,但它们可以通过链接预测分离。

image

PixelLink + VGG16 2s(2s表示预测图是原始图的一半)的结构。 fc6和fc7被提换成卷积层。上采样操作直接通过双线性插值完成。来自不同阶段的特征地图通过上采样和增加操作的级联进行融合。除pool5外的所有池层都采用2步幅,而pool5则采用1。因此,fc7的大小与conv5_3相同,因此合并时不需要上采样。conv 1x1,2(16) 代表具有2或16个内核的卷积层,分别用于文本/非文本预测或链接预测。

2.2 Linking Pixels Together

像素连接过程使用两个像素查看是否同时连接,这样才将它们看成一个连接组建。

2.3 Extraction of Bounding Box

使用miniAreaRect提取连接组建的最小外接矩形。这一步可以看出PixelLink和基于回归的方法之间的本质区别,即边界框直接从实例分割中获得,而不是位置回归。

2.4 Filter

使用边界框的几何特征进行过滤

3. Loss

$L = \lambda L _ { p i x e l } + L _ { l i n k }$

Lpixel 是像素分类Loss,Llink 是连接Loss。由于分任务更重要,λ设为2.

  • Pixel loss

    图片中文字的大小可能差异很大,这样对于那些小文字就不太友好。因此使用了一种新的损失函数,Balance Cross-Entropy(平衡交叉熵),就是为了让每个实例的权重相同。

    设第i个实例的面积为$S_i$ , 其上每个像素的权重为$w _ { i } = \frac { B _ { i } } { S _ { i } }$ ,$B_i$ 是实例平均像素数
    $B _ { i } = \frac { S } { N } , S = \sum _ { i } S _ { i } , \forall i \in { 1 , \ldots , N }$

    对于正负样本不平衡问题采用OHEM解决。最后的pixel loss,S实例总面积,r取3.
    $L _ { p i x e l } = \frac { 1 } { ( 1 + r ) S } W L _ { p i x e l _ { - } C E }$

  • Link loss

    正连接和负连接分别计算。
    $L_{link_{-} CE}$是链路预测的交叉熵损失矩阵。$W_{pos-link}$ 和 $W_{nge-link}$分别是正面和负面链接的权重。具体计算方法,对于像素 (i,j) 的第k个邻居:

    $\begin{aligned} L _ { l i n k _ { - } p o s } & = W _ { p o s - l i n k } L _ { l i n k _ { - } C E } \ L _ { l i n k _ { - } n e g } & = W _ { n e g _ { - } l i n k } L _ { l i n k _ { - } C E } \end{aligned}$

    $\begin{aligned} W _ { p o s - l i n k } ( i , j , k ) & = W ( i , j ) \left( Y _ { l i n k } ( i , j , k ) = = 1 \right) \ W _ { n e g _ { - } l i n k } ( i , j , k ) & = W ( i , j ) \left( Y _ { l i n k } ( i , j , k ) = = 0 \right) \end{aligned}$

4. Summary

  • 与CTPN,EAST,SegLink相比,PixelLink放弃了边框回归方法来检测文本行的bbox,而是采用实例分割方法,直接从分割的文本行区域得到文本行的bbox.PixelLink可以以更少额数据和更快地速度进行训练.
  • 假设提取特征的主干网络结构采用VGG16(当然你也可以采用其它主干网络结构),PixelLink不需要在imagenet预训练的模型上进行fine-tuned(即直接从头开始训练),而CTPN,EAST,SegLink都需要在imagenet预训练的模型上进行fine-tuned
  • 与CTPN,EAST,SegLink相比,PixelLink对感受野的要求更少,因为每个神经元值只负责预测自己及其邻域内的状态.
    与SegLink一样,不能检测很大的文本,这是因为link主要是用于连接相邻的segments,而不能用于检测相距较远的文本行

参考文章_1

参考文章_2

参考文章_3

Pixel-Anchor: A Fast Oriented Scene Text Detector with Combined Networks

论文

TextBoxes

1. Abstract

TextBoxes的灵感来源于SSD,SSD旨在检测图像中的一般物体,但无法识别具有极高宽高比的字。在TextBoxes中提出了文本框图层来解决这个问题.

2. Architecture

image

TextBoxes架构TextBoxes是一个28层完全卷积网络。其中13个是从VGG-16继承的。在VGG-16层之后增加了9个额外的卷积层。文本框图层连接到6个卷积图层。在每个Map上,文本框图层预测72个向量,它们是12个默认框的分数(2-d)和偏移量(4-d)。对所有文本框图层的聚合输出应用非最大抑制。

  • 文本框层

    假设图像和特征图大小分别是Xim\Yim)和Xmap\Ymap)。在feature map位置(i,j)一个默认框$\mathbf { b } _ { 0 } = \left( x _ { 0 } , y _ { 0 } , w _ { 0 } , h _ { 0 } \right)$,文本框输出层预测输出$( \Delta x , \Delta y , \Delta w , \Delta h , c )$,对应在原图上$\mathbf { b } = ( x , y , w , h )$

    $\begin{aligned} x & = x _ { 0 } + w _ { 0 } \Delta x \ y & = y _ { 0 } + h _ { 0 } \Delta y \ w & = w _ { 0 } \exp ( \Delta w ) \ h & = h _ { 0 } \exp ( \Delta h ) \end{aligned}$

与一般物体不同,单词文本倾向于具有较大的宽高比。因此,使用包含具有较大宽高比的“长”默认框。具体而言,我们为默认box定义6种纵横比,包括1,2,3,5,7和10。但是,这会使默认框在水平方向密集而垂直稀疏,这会导致较差的匹配框。为了解决这个问题,每个默认框都设置了垂直偏移。

image

而且,在文本框图层中,采用不规则的1 5卷积滤波器而不是标准的3 3卷积滤波器。这种初始式滤波器可以产生矩形的接收区域,它可以更好地融合具有较大纵横比的字,还可以避免方形接收区带来的噪声信号。

3.Loss

$L ( x , c , l , g ) = \frac { 1 } { N } \left( L _ { \mathrm { conf } } ( x , c ) + \alpha L _ { \mathrm { loc } } ( x , l , g ) \right)$

分为位置loss和置信度loss的加权和

参考文章_1

参考文章_2

参考文章_3

TextBoxes++

TextSpotter

SPCNet

FOST

  • 论文
  • 代码没放出来,github上别人实现的都没有识别分支(*  ̄ー ̄),这给EAST有什么区别,你们实现了什么啊

image

看到没就是快

image

https://zhuanlan.zhihu.com/p/38655369
https://www.cnblogs.com/skyfsm/p/9776611.html
https://zhuanlan.zhihu.com/p/39796620