1、一些资源
1.1、原始论文:https://arxiv.org/pdf/1609.03605.pdf
1.2、一些讲的比较好的中文博客,可以先看中文博客,再看原始论文:
https://blog.csdn.net/zchang81/article/details/78873347
https://blog.csdn.net/SIGAI_CSDN/article/details/80800131
https://zhuanlan.zhihu.com/p/34757009
https://zhuanlan.zhihu.com/p/43145228
http://www.neurta.com/node/390
1.3、代码(tf版及caffe版):https://github.com/YCG09/chinese_ocr
https://github.com/tianzhi0549/CTPN
2、论文解读
2.1算法效果
首先分析文本检测的特点:文本检测和一般目标检测的不同——文本线是一个sequence(字符、字符的一部分、多字符组成的一个sequence),而不是一般目标检测中只有一个独立的目标。要检测出一个完整的文本线,同一文本线上不同字符可能差异大,距离远,要作为一个整体检测出来难度比单个目标更大——因此,作者认为预测文本的竖直位置(文本bounding box的上下边界)比水平位置(文本bounding box的左右边界)更容易,所以ctpn的亮点1、创新性的提出了vertical anchor,这是提高文本行检测精度的关键。同时,同一文本线上不同字符可以互相利用上下文,可以用sequence的方法比如RNN来表示,所以亮点2、将lstm引入到了网络里面,并且和cnn无缝对接,发挥lstm的记忆作用,根据前后的anchor 序列来提取这种相互之间的关系特征,输出给fc层,给每个anchor打分,最后用文本线构造法,将anchor连接起来,得到文本行。这两大亮点使得ctpn在文本行检测的精确度方面有了很大的提升,先上图形象的感受一下ctpn的效果,然后再具体看数字精确的对比。如下:
2.2 算法结构
先上图,下面就针对这张算法整体结构图来说
1、用VGG16的前5个Conv stage(到conv5)得到feature map(W*H*C)这里C是特征图的个数为512
2、在Conv5的feature map的每个位置上取3*3*512*512([filter_height, filter_width, in_channels, out_channels])
的窗口做卷积,得到W*H*512的特征图,这些特征将用于预测该位置k个anchor(anchor的定义和Faster RCNN类似)对应的类别信息,位置信息。
3、将每一行的3*3*512的卷积得到的512维的特征向量输入到双向lstm里面去,lstm的隐含层节点个数是128,双向则为256。在不考虑batchsize的情况下,
一共有H*W个512维的特征向量进入双向lstm,W也代表类似于时序了,输出是128,两个lstm一个是从1到w,一个是从w到1的顺序输入lstm,最终BLSTM得到256维的特征,将短边缩放到600的情况下,有lstm0.14s每张,没有lstm的话0.13s,有和没有的效果对比如下:
4、最后连接两个fc,fc的输入是BLSTM的输出256D的特征,输出是512D,一共有H*W个,注意,有的版本的代码里面fc使用1*1的卷积实现的,1*1卷积可以减少参数,但是效果基本没差别(咨询过了)
其中第一个fc计算的是bbox,bbox应该是h*w*4,ctpn中只预测h和y值,所以只有h*w*2个,第二个fc计算的是score,分别表示是背景的score和是文本的score,损失函数是softmax loss
ctpn中的num_anchors(k)=10,整张图片上有w*h*num_anchors*2个score和coordinate,这里默认了每个anchor的width是16(也就是下面贴的代码里面的anchor_scales=16),上图中那些红色的细长矩形,它们的宽度是一定的,都是16。所以,每次在做训练之前先要把标注的文本行变成16宽的小框,ctpn的代码里面有这个脚本。高度从11~283(每次除以0.7),Anchor必须是对应原图尺度!
这样看来side-refinement并没有在代码里面实现,但是在后面论文里面的loss里面有体现
当然anchor_scale也可以设置成宽度为[8,16,32]这种多尺度的情况,那么每个像素点的num_anchors(k)=30了。
回归的高度h及中心坐标y,和gt(带*)的高度h和中心坐标y的计算方式如下,带a的表示是anchor,损失函数是smooth L1:
score阈值设置:0.7 (+NMS),
5、用文本线构造算法,把分类得到的文字的proposal(上中的细长的矩形,score>0.7)合并成文本线。
主要思想:每两个相近的proposal组成一个pair,合并不同的pair直到无法再合并为止(没有公共元素)
如果两个proposal,Bi和Bj组成pair去合并的条件,Bj->Bi,且Bi->Bj(Bj→Bi表示Bj是Bi的最好邻居):
Bj->Bi条件1:Bj是Bi的邻居中距离Bi最近的,且该距离小于50个像素
Bj->Bi条件2:Bj和Bi的vertical overlap大于0.7
固定要regression的box的宽度和水平位置会导致predict的box的水平位置不准确,所以作者引入了side-refinement,用于水平位置的regression,损失函数是smooth L1函数
where xside is the predicted x-coordinate of the nearest horizontal side (e.g., left or right side) to current anchor. x∗ side is the ground truth (GT) side coordinate in x-axis, which is pre-computed from the GT bounding box and anchor location. cax is the center of anchor in x-axis. wa is the width of anchor, which is fixed, wa = 16
作者解释,side-proposals被定义为开始和结束提议,仅使用side-proposal的偏移量来细化最终的文本行边界框。 side-refinement进一步提高了定位精度,使得SWT和 Multi-Lingual datasets的性能提高约2%。 另外,作者说在第一张图里面的模型结构中同时预测了side-refinement的偏移量,它不是通过额外的后处理步骤计算出来的,这一点体现在loss function里,但是代码中并没有这部分,可能代码是爱好者写的,并不是作者的源代码,所以会有出入,后面的loss function的补充里面有说明这一点。
具体详细如何做的,可以参考的http://www.neurta.com/node/390,写的比较详细
有side-refinement和没有side-refinement的对比:
下图是整个ctpn结构的代码部分,可以帮助理解
补充:
Loss分为3个部分:
, 是各任务的权重系数, , , 是归一化参数,表示对应任务的样本数量。
训练细节
每个minibatch同样采用“Image-centric”的采样方法,每次随机取一张图片,然后在这张图片中采样128个样本,并尽量保证正负样本数量的均衡。卷积层使用的是Image-Net上无监督训练得到的结果,权值初始化使用的是均值为0,标准差为0.01的高斯分布。SGD的参数中,遗忘因子是0.9,权值衰减系数是0.0006。前16k次迭代的学习率是0.001,后4k次迭代的学习率是0.0001。
由于加入LSTM,所以CTPN对水平文字检测效果超级好。CTPN加入了双向LSTM学习文字的序列特征,有利于文字检测。但是引入LSTM后,在训练时很容易梯度爆炸,需要小心处理。