多方向文字检测-AdvancedEast详解
前言
AdvancedEast是场景文字检测算法,基于EAST算法,对EAST在长文本检测地方的缺陷进行了重大改进,使长文本预测更加准确。总体来说AdvancedEast检测算法在多角度文字检测方面表现良好,没有明显的缺陷。出于对作者的尊重,给出github链接AdvancedEast
作者由于时间问题给出的资料非常有限,网上大多的资料也是基本照搬作者的描述,本文将对AdvancedEast的实现细节进行详细的讲解。AdvancedEast在整体的设计上还是延续East,在最终的输出与推测部分进行了精巧的设计,也是本文重点介绍部分。
structure
在模型结构上面,AdvancedEast与EAST差别不大(下方图片分别为AdvancedEast、EAST结构图),都是由特征提取、特征融合、输出三部分组成。
特征提取部分,AdvancedEast采用vgg16而EAST在论文中采用PVANet,但是在github实现上面EAST多用vgg16或resnet50。AdvancedEast利用在ImageNet数据集上预训练的卷积网络参数初始化,在VGG16的4个阶段输出作为特征融合阶段的输入,其大小分别为输入图像的1/4 1/8 1/16 1/32(对应图中f4、f3、f2、f1)
特征融合部分,AdvancedEast沿用EAST结构,使用多尺度特征融合的办法解决目标检测中的难题-多尺寸目标检测。目标检测算法中非常需要注意的是感受野的问题,感受野过小容易造成大目标检测不准确,感受野过大会导致丢失的信息过多,在小目标检测上面表现不佳。将不同感受野的feature map进行融合,可以补充不同尺寸目标信息来实现对不同尺寸物体的检测。
每个融合阶段,特征提取部分不同阶段的输出感受野不一样,特征图尺寸也不一样(相邻阶段输出的feature map是2倍关系),所以需要将感受野更大的feature map输入到unpooling层扩大其大小;然后,与当前层特征图进行合并(通道);合并之后虽然包含了不同尺度的feature map,但是其中还是有大量的没用的信息,这种信息会加大计算代价,而且现在的合并只是单纯的进行通道上的合并,还需要进行进一步的融合;将合并后的结果通过1×1的卷机神经网络减少通道数量和计算量;再用3×3的卷积神经网络将局部信息融合以最终产生该合并阶段的输出;
此次类推将每个阶段的feature map进行合并,如图中特征融合部分所示,在最后一个合并阶段之后,conv3×3层会生成合并分支的最终特征图并将其送到输出层。
输出部分,这部分AdvancedEast进行了重要的改进,也是跟EAST区别最大的地方,下面会单独进行展开说明。
output layer
输出部分是AdvancedEAST最大的改动地方,主要是解决EAST在长文本预测的限制问题,所以在进行输出部分讲解之前,先介绍下EAST为什么在长文本预测表现不佳。
下图是EAST的输出,输出的feature map是原图像的四分之一。
score map:置信度,点在文本框内的概率
RBOX:4个通道分别表示从像素位置到矩形的顶部,右侧,底部,左侧边界的4个距离
text rotation angle:表示文本框的旋转角度
QUAD:8个通道分别表示从矩形的四个顶点到像素位置的坐标偏移,由于每个距离偏移量都包含两个数字(Δxi;Δyi)
RBox与QUAD两种模式选一即可,不管选择哪一种都有一个共用的问题,这里以RBox举例,在预测边框和顶点之前,第一步要根据score map筛选出文本框内的点,下图是举例说明确定边框的过程,下图表示一张图片中的一个文本框,框内的点都有个预测到四条边的距离,根据文本内每个点所预测的距离(顶点)进行加权平均,得出边框或者顶点。在文本框比较小的时候没有问题,但是最终输出的feature map中每个点都有感受野的限制,当文本很长的时候,用一端的点去预测另外一端的边的距离的时候,就会出现携带信息没有那条边的信息,所以EAST在预测长文本的时候会出现断裂或者预测不出来的情况。
AdvancedEast算法采用另外的一种思路解决。先看一下输出。
score map:和EAST一样,点在文本内的置信度
vertex code:第一通表示是否是边界元素的置信度。第二通表示是头/尾元素,0表示头部元素,1表示尾部元素
vertex geo:4通分别代表左上(右上)X、左上(右上)Y、左下(右下)X、左下(右下)Y,这里不是真正的X\Y坐标,而是根据当前点坐标的X/Y偏移量
这里面不太好理解的应该是vertex geo,为什么同样是4通的输出,但是表达的含义不同,这里主要的原因是,为了解决East感受野的问题,AdvancedEast不再用所有的点进行预测顶点了,而是用头部元素预测左上、左下点,尾部元素预测右上右下点。也就是说vertex geo的输出只对头部和尾部元素有意义,且根据预测出的头/尾元素进行加权平均得到4个顶点。这样说有点抽象,下面会对预测过程展开讲解。
预测过程
预测过程整体的流程如下:
- 根据score map输出的值确定activatin point
- 遍历所有activation point,在feature map中左右相邻的activation point合并形成若干region list
- 遍历所有region list,在feature map中上下相邻的region list合并形成region group
- 遍历region group中的点,根据vertex code输出的值确定头/尾元素
- 每个region group中的头部(尾部)元素预测的vertex geo进行加权平均得到最终文本框顶点
下面用一张示例图模拟整个过程,为了简化问题,这里模拟一张图片中只有一个文本域的情况,图中每个点有7通取值,对应模型的输出(score map、vertex code、vertex geo)
第一步遍历feature map中所有点,这里feature map指模型的输出(score map、vertex code、vertex geo),筛选出score map值高于threshole的点,得到activation point(激活元素),如下图,得到所有activation point(文本框内元素)
遍历上一步获得的所有activation point,将在feature map中左右相邻(X坐标相差1,Y坐标相同)的activation point进行合并,得到若干 region list,如下图,红色虚线框表示region list。
遍历上一步得到的region list,将feature map中上下相邻的region list进行合并成为region group,具体上下相邻规则是如果region list1中所有元素向下平移一个单位后,和其他的region list有重合点,则进行合并,否则不进行合并。
这里的region group是文本域的大致位置,为什么要这么说,在我的图片示例中展示的是一个文本的情况,并且是所有的点很规整的情况,但是在真正的预测的时候并不是所有的点都会预测出来或者可能会出现噪音点。并不能根据这些点很完整的确定出具体的文本,还需要进行进一步的计算。
遍历每个region group中的点,根据vertex code输出的值找到其中的头/尾元素,头/尾需要满足的规则是vertex code中第一通输出的是否是边界元素置信度的值高于阈值,且vertex code中的分类置信度满足阈值(默认情况下阈值为0-0.1表示头部元素,0.9-1表示尾部元素),如代码中红线部分
现在确定了每个region group中的头尾元素,如下图所示,根据头部(尾部)元素所预测的左上(右上)X、左上(右上)Y、左下(右下)X、左下(右下)Y偏移量进行加权平均,确定最终预测的4个顶点。具体的加权平均的方式如下,n表示当前文本域内边界元素数量
q
u
a
d
(
p
v
)
=
∑
i
=
1
n
s
c
o
r
e
i
∗
p
v
i
∑
i
=
1
n
s
c
o
r
e
i
quad(pv)= \frac{\sum_{i=1}^nscore_i*pv_i}{\sum_{i=1}^nscore_i}
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.03588em;">q</span><span class="mord mathdefault">u</span><span class="mord mathdefault">a</span><span class="mord mathdefault">d</span><span class="mopen">(</span><span class="mord mathdefault">p</span><span class="mord mathdefault" style="margin-right: 0.03588em;">v</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height: 2.488004em; vertical-align: -0.994002em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 1.494002em;"><span class="" style="top: -2.305708em;"><span class="pstrut" style="height: 3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position: relative; top: -0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.804292em;"><span class="" style="top: -2.40029em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span class="" style="top: -3.2029em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">n</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.29971000000000003em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.16666666666666666em;"></span><span class="mord mathdefault">s</span><span class="mord mathdefault">c</span><span class="mord mathdefault">o</span><span class="mord mathdefault" style="margin-right: 0.02778em;">r</span><span class="mord"><span class="mord mathdefault">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.31166399999999994em;"><span class="" style="top: -2.5500000000000003em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span></span></span><span class="" style="top: -3.23em;"><span class="pstrut" style="height: 3em;"></span><span class="frac-line" style="border-bottom-width: 0.04em;"></span></span><span class="" style="top: -3.6897100000000003em;"><span class="pstrut" style="height: 3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position: relative; top: -0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.804292em;"><span class="" style="top: -2.40029em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span class="" style="top: -3.2029em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">n</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.29971000000000003em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.16666666666666666em;"></span><span class="mord mathdefault">s</span><span class="mord mathdefault">c</span><span class="mord mathdefault">o</span><span class="mord mathdefault" style="margin-right: 0.02778em;">r</span><span class="mord"><span class="mord mathdefault">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.31166399999999994em;"><span class="" style="top: -2.5500000000000003em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span><span class="mord mathdefault">p</span><span class="mord"><span class="mord mathdefault" style="margin-right: 0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.31166399999999994em;"><span class="" style="top: -2.5500000000000003em; margin-left: -0.03588em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.994002em;"><span class=""></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></span><br> <span class="katex--inline"><span class="katex"><span class="katex-mathml">
p
v
i
pv_i
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.625em; vertical-align: -0.19444em;"></span><span class="mord mathdefault">p</span><span class="mord"><span class="mord mathdefault" style="margin-right: 0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.31166399999999994em;"><span class="" style="top: -2.5500000000000003em; margin-left: -0.03588em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span></span></span></span></span>:当前边界元素的坐标与预测的x、y偏移量相加后的结果,换句话说是预测的顶点坐标<br> <span class="katex--inline"><span class="katex"><span class="katex-mathml">
s
c
o
r
e
i
score_i
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.58056em; vertical-align: -0.15em;"></span><span class="mord mathdefault">s</span><span class="mord mathdefault">c</span><span class="mord mathdefault">o</span><span class="mord mathdefault" style="margin-right: 0.02778em;">r</span><span class="mord"><span class="mord mathdefault">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.31166399999999994em;"><span class="" style="top: -2.5500000000000003em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span></span></span></span></span>:当前边界元素的置信度(对应输出的第二通)</p>
这里有点小细节需要注意,前面有提到,最终的输出不是原图size,而是其1/4,所以feature map中的坐标要对应回原图坐标需要进行处理(只对feature map中的坐标对应回原图坐标,预测的偏移量是原图的偏移量不需要进行处理),处理方式如下
p
x
=
(
x
+
0.5
)
∗
4
px=(x + 0.5) * 4
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.625em; vertical-align: -0.19444em;"></span><span class="mord mathdefault">p</span><span class="mord mathdefault">x</span><span class="mspace" style="margin-right: 0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mopen">(</span><span class="mord mathdefault">x</span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord">0</span><span class="mord">.</span><span class="mord">5</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height: 0.64444em; vertical-align: 0em;"></span><span class="mord">4</span></span></span></span></span></span><br> <span class="katex--display"><span class="katex-display"><span class="katex"><span class="katex-mathml">
p
y
=
(
y
+
0.5
)
∗
4
py=(y + 0.5) * 4
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.625em; vertical-align: -0.19444em;"></span><span class="mord mathdefault">p</span><span class="mord mathdefault" style="margin-right: 0.03588em;">y</span><span class="mspace" style="margin-right: 0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right: 0.03588em;">y</span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord">0</span><span class="mord">.</span><span class="mord">5</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right: 0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height: 0.64444em; vertical-align: 0em;"></span><span class="mord">4</span></span></span></span></span></span><br> <img src="https://img-blog.csdnimg.cn/20200303144106592.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpZ2UxOTkw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
经过上述过程完成文本检测,效果图如下。