CTPN(Detecting Text in Natural Image with Connectionist Text Proposal Network)算法详解

《Detecting Text in Natural Image with Connectionist Text Proposal Network》,发表在ECCV2016,算是一个使用比较多效果较好的较为经典的一个文字检查算法了,CVPR2017年中的一篇名为SegLink的文章灵感也来自于此。代码地址:https://github.com/tianzhi0549/CTPN ,这是其中的一个作者提供的代码,我看的是tensorflow版本的实现,tensorflow版本代码地址:https://github.com/eragonruan/text-detection-ctpn

首先要明确的是这篇文章提出的算法是针对水平文本来做的,倾斜和竖直的文本不适用,如果不知道RPN网络的最好先看一下Faster R-cnn,这样更容易弄懂这篇文章介绍的算。

文章思路是借鉴RPN网络,但是RPN是最初提出来是在Faster R-cnn中,是用来做物体检测的。文章认为不同于物体检测,文本的长度是不固定的,它的长宽比也不像通常物体那么有规则,如果单纯用RPN提出的框来检测文本,很容易出现误差的情况,所以文章将一个文本框分成多个宽为16的小框组成,如下图所示(左边为直接采用RPN检测文本框的结果,右边为RPN输出多个小框来检测文本的结果)。这样通过检测出的多个小框组成最终的文本框能够得到更为准确的结果。下面来看一下它的具体算法。
1.png

一、网络结构

文章采用了CNN和RNN结合的网络架构,backbone采用的是VGG16,如下图所示。
2.png

输入一张图片后,经过VGG卷积后得到,提取出最后一层卷积的feature map称为conv5,将得到的conv5经过 3 × 3 3\times 3 的卷积,将卷积后的结果输入一个双向的RNN层,最后经过一层全连接层得到输出结果。输出有三个结果,一个是anchor的分数,一个是anchor回归的参数,一个是新提出的side-refinement输出(这个稍后会讲)

还要提一下的是,这个网络的架构。文章中先是说明了直接使用CNN的结果来输出最终结果,但是文中认为文字检测还有上下文的关系,所以加入RNN能有效的提高检测效果。文章另一个版本是将CNN的输出输入RNN,这样实现了CNN和RNN的无缝连接,也提高了检测效果,对比如下图所示,上边为只有CNN的输出结果,下边为CNN和RNN的输出结果
3.png

二、标签的生成

因为这里网络的输出不是一个文本框,而是文本框的一部分,所以训练的时候,标签也是文本框的一部分。groundtruth就是将标定的文本框(一般为任意的四边形)变成一个矩形(例如可以求最小外接矩形),得到矩形后将矩形按照宽为16划分为对个小的矩形,这些小矩形就是groundtruth,它们一起组成文本框。

又因为采用了RPN的结构,RPN网络的输出是不同尺寸的anchor(文章采用了10中anchor,这些anchor宽都为16,高不同,高从11到273,从11开始依次除以0.7得到)。所以正样本和负样本是一系列的anchor box。

正样本定义为:

  1. 与groundtruth的IoU>0.7的anchor为正
  2. 与groundtruth的Iou最大的anchor为正(这个条件是为了对小文本框的支持更好)

将与groundtruth的IoU<0.5的anchor定义为负样本。

其他的设定与RPN相同,比如输出的是anchor的分数和anchor的回归值,但是这里的回归只有y值和y方向的中心点位置,因为anchor的宽是固定的16。

还有一点不一样的是这里输出除了有anchor的分数和anchor的回归值外,还会输出一个叫side-refinement的信息。文章认为因为存在y方向的回归操作所以在y方向的输出比较准确,但是文本框被序列化为宽16像素的小框组成,这样可能会导致水平方向的输出不是很准,如下图所示(红框为利用side-refinement操作后的结果,黄框为未使用side-refinement操作的结果)。这里回归的是组成文本框的头和尾的小框的位置(tensorflow版本的代码并未实现这一部分)。
4.png

三、损失函数的定义

损失函数定义如下

L ( s j , v j , o k ) = 1 N i L s c l ( s i , s i ) + λ 1 N v L v r e ( v j , v j ) + λ 2 N o k L o r e ( o k , o k ) L(s_{j}, v_{j}, o_{k})=\frac{1}{N}\sum_{i}L^{cl}_{s}(s_{i},s^{*}_{i})+\frac{\lambda_{1}}{N_{v}}{L^{re}_{v}(v_{j},v^{*}_{j})}+\frac{\lambda_{2}}{N_{o}}\sum_{k}L^{re}_{o}(o_{k}, o^{*}_{k})

训练时每个anchor是一个训练样本, i i 为minibatch中一个anchor的索引。 s i s_{i} 是对一个anchor预测的分数值, s i = { 0 , 1 } s^{*}_{i}=\{0,1\} 为真值。 j j 为valid anchors中的索引,valid anchors定义为 s j = 1 s^{*}_{j}=1 的anchor或者与groundtruth的IoU>0.5的anchor。 v j v_{j} v j v^{*}_{j} 分别是预测的回归值和真实的回归值。 k k 值为side-anchor,side-anchor定义为离标定的文本框左侧或者右侧的水平距离在一定值(例如32像素)的anchor。 o k o_{k} o k o^{*}_{k} 为预测的回归值和真实的回归值。 L s c l L^{cl}_{s} 为softmax loss, L v r e L^{re}_{v} L o r e L^{re}_{o} 为smooth L1计算的回归损失。 λ 1 = 1.0 \lambda_{1}=1.0 λ 2 = 2.0 \lambda_{2}=2.0 。式中 N s , N v , N o N_{s},N_{v},N_{o} 分别为参与各损失函数计算的anchor box的个数。

损失函数中, v = { v c , v h } v=\{v_{c},v_{h}\} v = { v c , v h } v^{*}=\{v^{*}_{c},v^{*}_{h}\} ,计算方式如下

v c = ( c y c y a ) / h a , v h = l o g ( h / h a ) v_{c}=(c_{y}-c^{a}_{y})/h^{a},v_{h}=log(h/h^{a})
v c = ( c y c y a ) / h a , v h = l o g ( h / h a ) v^{*}_{c}=(c^{*}_{y}-c^{a}_{y})/h^{a},v^{*}_{h}=log(h^{*}/h^{a})

其中 c y a c^{a}_{y} h a h^{a} 是anchor box的中心点的y坐标和高。相似的, c y c_{y} h h 为预测值, c y c^{*}_{y} h h^{*} 为groundtruth。

损失函数中, o o o o_{*} 计算方式如下。
o = ( x s i d e c x a ) / w a , o = ( x s i d e c x a ) / w a o=(x_{side}-c^{a}_{x})/w^{a},o^{*}=(x^{*}_{side}-c^{a}_{x})/w^{a}

其中, x s i d e x_{side} 表示的是文本框的side anchor的x坐标,相似的 x s i d e x^{*}_{side} 为真值。 w a = 16 w^{a}=16 表示anchor的宽。

四、输出回归后的anchor的合成方式

如何将输出的anchor合成为文本框,判断两个anchor属于同一个文本框应满足下列条件:

  1. 两个框的水平距离是最近的
  2. 两个框的水平距离小于50像素
  3. 两个框垂直方向的重叠大于0.7

如果两个anchor相互都满足上述条件则认为它们属于同一个文本框。

具体实现可以参考tensorflow版本代码,因为实现和文章还有些不一样的地方,比如anchor的大小,实现的anchor的高取值为[11, 16, 23, 33, 48, 68, 97, 139, 198, 283]而不是文章中的11到273,还有代码没有实现 L o r e L^{re}_{o} 的计算等等。

到这里CTPN就介绍完了。

中文本定位与识别的评测方法

欢迎加入OCR交流群:785515057

猜你喜欢

转载自blog.csdn.net/liuxiaoheng1992/article/details/86176989