• CTPN


    CTPN

    Detecting Text in Natural Image with Connectionist Text Proposal Network

    基于caffe实现——CTPN

    对于复杂场景的文字识别,首先要定位文字的位置,即文字检测。这一直是一个研究热点。

    CTPN是在ECCV 2016提出的一种文字检测算法。CTPN结合CNN与LSTM深度网络,能有效的检测出复杂场景的横向分布的文字,效果如图1,是目前比较好的文字检测算法。由于CTPN是从Faster RCNN改进而来,本文默认读者熟悉CNN原理和Faster RCNN网络结构。

    网络结构

    原始CTPN只检测横向排列的文字。CTPN结构与Faster R-CNN基本类似,但是加入了LSTM层。假设输入(N) Images:

    • 首先VGG提取特征,获得大小为(N imes C imes H imes W)的conv5 feature map

    • 之后在conv5上做(3 imes 3)的滑动窗口,即每个点都结合周围(3 imes 3)区域特征获得一个长度为(3 imes 3 imes C)的特征向量。输出(N imes 9C imes H imes W)的feature map,该特征显然只有CNN学习到的空间特征。

    • 再将这个feature map进行Reshape

      [Reshape: N imes 9C imes H imes W ightarrow (NH) imes W imes 9C ]

    • 然后以(Batch=NH)且最大时间长度(T_{max}=W)的数据流输入双向LSTM,学习每一行的序列特征。双向LSTM输出((NH) imes W imes 256),再经Reshape恢复形状:

      [Reshape:(NH) imes W imes 256 ightarrow N imes 256 imes H imes W ]

      该特征既包含空间特征,也包含了LSTM学习到的序列特征。

    • 然后经过FC层,变为(N imes 512 imes H imes W)的特征

    • 最后经过类似Faster R-CNN的RPN网络,获得text proposals

    img

    更具体的网络结构,请使用netscope查看CTPN的deploy.prototxt网络配置文件。

    这里解释一下conv5 feature map如何从(N imes C imes H imes W)变为(N imes 9C imes H imes W)

    img

    在原版caffe代码中是用im2col提取每个点附近的9点临近点,然后每行都如此处理:

    [H imes W ightarrow9 imes H imes W ]

    接着每个通道都如此处理:

    [C imes H imes W ightarrow 9C imes H imes W ]

    其使用的im2col是用于卷积加速的操作,即将卷积变为矩阵乘法,从而使用Blas库快速计算。

    特别说明:上述是对原Paper+Caffe代码的解释,其它代码实现异同不在本文讨论范围内!

    原版的ctpn,是用caffe中的im2coll把周围3x3的点取出来形成N(9C)HW,并不是卷积。至于caffe im2coll是一种把卷积变换成矩阵乘法的内部操作,以便用cublas加速卷积计算。

    到了tf实现,没这个操作,所以直接卷积(C ightarrow 9C)代替了im2col操作。

    接下来,文章围绕下面三个问题展开:

    1. 为何使用双向LSTM
    2. 如何通过FC层输出产生图2-b中的Text proposals
    3. 如何通过Text proposals确定最终的文本位置,即文本线构造算法

    为何使用双向LSTM?

    CNN学习的是感受野内的空间信息,LSTM学习的是序列特征。对于文本序列检测,显然既需要CNN抽象空间特征,也需要序列特征(毕竟文字是连续的)。

    CNN卷积计算如下图:

    img

    CTPN中使用双向LSTM,相比一般单向LSTM有什么优势?双向LSTM实际上就是将2个方向相反的LSTM连起来,如下图

    img

    一般来说,双向LSTM都好于单向LSTM。例如:

    我的手机坏了,我打算____一部新手机。
    

    假设使用LSTM对空白部分填词。如果只看横线前面的词,“手机坏了”,那么“我”是打算“修”还是“买”还是“大哭一场”?双向LSTM能看到后面的词是“一部新手机“,那么横线上的词填“买“的概率就大得多了。显然对于文字检测,这种情况也依然适用。

    如何通过"FC"卷积层输出产生图2-b中的Text proposals?

    img

    CTPN通过CNN和BLSTM学到一组“空间 + 序列”特征后,在"FC"层后接入RPN网络。这里的RPN与Faster R-CNN类似,分为两个分支:

    1. 左边分支用于bounding box regression。由于FC层feature map每个点配备了10个Anchor,同时只回归中心y坐标与高度2个值,所以(rpn\_bboxp\_red)有20个channels
    2. 右边分支用于Softmax分类Anchor

    具体RPN网络与Faster R-CNN完全一样,所以不再介绍,只分析不同之处。

    竖直Anchor定位文字位置

    由于CTPN针对的是横向排列的文字检测,所以其采用了一组(10个)等宽度的Anchors,用于定位文字位置。Anchor宽高为:

    [egin{matrix}widths=[16]\heights-[11,16,23,33,48,68,97,139,198,283]end{matrix} ]

    需要注意,由于CTPN采用VGG16模型提取特征,那么conv5 feature map的宽高都是输入Image的宽高的(frac{1}{16})。同时fc与conv5 width和height都相等。

    如下图所示,CTPN为fc层feature map每一个点都配备10个上述Anchors。

    img

    这样设置Anchors是为了:

    1. 保证在(x)方向上,Anchor覆盖原图每个点且不相互重叠。
    2. 不同文本在(y)方向上高度差距很大,所以设置Anchors高度为11~283,用于覆盖不同高度的文本目标。
    • 可能有人会问Anchor大小为什么对应原图尺度,而不是conv5/fc特征尺度?
      • 因为Anchor是目标的候选框,经过后续分类+位置修正获得目标在原图尺度的检测框。那么这就要求Anchor必须是对应原图尺度!除此之外,如果Anchor大小对应conv5/fc尺度,那就要求Bounding box regression把很小的框回归到很大,这已经超出Regression小范围修正框的设计目的。

    获得Anchor后,与Faster R-CNN类似,CTPN会做如下处理:

    1. Softmax判断Anchor中是否包含文本,即选出Softmax score大的正Anchor
    2. Bounding box regression修正包含文本的Anchor的中心y坐标高度

    注意,与Faster R-CNN不同的是,这里Bounding box regression不修正Anchor中心x坐标和宽度。具体回归方式如下:

    [egin{matrix}v_c=frac{(c_y-c_y^a)}{h^a}&v_h=log(frac{h}{h^a})\v_c^*=frac{(c^*_y-c^a_y)}{h^a}&v^*_h=log(frac{h^*}{h^a})end{matrix} ]

    其中,(v=(v_c,v_h))是回归预测的坐标,(v=(v^*_c,v^*_h))是Ground Truth,(c^a_h)(h^a)是Anchor的中心(y)坐标和高度。

    Anchor经过上述Softmax和(y)方向bounding box regeression处理后,会获得下图所示的一组竖直条状text proposal。后续只需要将这些text proposal用文本线构造算法连接在一起即可获得文本位置。

    img

    在论文中,作者也给出了直接使用Faster R-CNN RPN生成普通proposal与CTPN LSTM+竖直Anchor生成text proposal的对比,如下图,明显可以看到CTPN这种方法更适合文字检测。

    img

    文本线构造算法

    在上一个步骤中,已经获得了图7所示的一串或多串text proposal,接下来就要采用文本线构造办法,把这些text proposal连接成一个文本检测框。

    img

    为了说明问题,假设某张图有图9所示的2个text proposal,即蓝色和红色2组Anchor,CTPN采用如下算法构造文本线:

    1. 按照水平(x)坐标排序Anchor
    2. 按照规则依次计算每个Anchor (box_i)(pair(box_j)),组成(pair(box_i,box_j))
    3. 通过(pair(box_i,box_j))建立一个Connect graph,最终获得文本检测框

    下面详细解释。假设每个Anchor index如绿色数字,同时每个Anchor Softmax score如黑色数字。

    文本线构造算法通过如下方式建立每个Anchor (box_i)(pair(box_i,box_j))

    正向寻找:

    1. 沿水平正方向,寻找和(box_i)水平距离小于50像素的候选Anchor(原文中一次向前只找50像素每,个Anchor宽16像素,也就是最多正向找50/16=3个Anchor)
    2. 从候选Anchor中,挑出与(box_i)竖直方向(overlap_v>0.7)的Anchor
    3. 挑出符合条件2中Softmax score最大的(box_j)

    再反向寻找:

    1. 沿水平负方向,寻找和(box_j)水平距离小于50的候选Anchor
    2. 从候选Anchor中,挑出与(box_j)竖直方向(overlap_v>0.7)的Anchor
    3. 挑出符合条件2中Softmax score最大的(box_k)

    最后对比(score_i)(score_k)

    1. 如果(score_ige score_k),则这是一个最长连接,那么设置(Graph(i,j)=True)
    2. 如果(score_i< score_k),说明这不是一个最长的连接(即该连接肯定包含在另外一个更长的连接中)。
    class TextProposalGraphBuilder:
    
        ......
    
        def is_succession_node(self, index, succession_index):
            precursors=self.get_precursors(succession_index)
            # index 为上文中的 i, succession_index 为 j, precursors 为负向搜索找到的 k
            if self.scores[index]>=np.max(self.scores[precursors]):
                return True
            return False
    
        def build_graph(self, text_proposals, scores, im_size):
            self.text_proposals=text_proposals
            self.scores=scores
            self.im_size=im_size
            self.heights=text_proposals[:, 3]-text_proposals[:, 1]+1
    
            boxes_table=[[] for _ in range(self.im_size[1])]
            for index, box in enumerate(text_proposals):
                boxes_table[int(box[0])].append(index)
            self.boxes_table=boxes_table
    
            graph=np.zeros((text_proposals.shape[0], text_proposals.shape[0]), np.bool)
    
            for index, box in enumerate(text_proposals):
                # 沿水平正方向寻找所有overlap_v > 0.7匹配
                successions=self.get_successions(index)
                if len(successions)==0:
                    continue
    
                # 找匹配中socre最大的succession_index(即上文j)
                succession_index=successions[np.argmax(scores[successions])] 
    
                # 沿水平负方向寻找socre最大的 k,如果socre_i >= score_k 则是一个最长连接
                if self.is_succession_node(index, succession_index):
                    # NOTE: a box can have multiple successions(precursors) if multiple successions(precursors)
                    # have equal scores.
                    # 设置 Graph connection (i,j)为 True
                    graph[index, succession_index]=True
            return Graph(graph)
    

    img

    举例说明,如上图,Anchor已经按照(x)顺序排列好,并具有图中的Softmax score(这里的score是随便给出的,只用于说明文本线构造算法):

    1. (i=3)(box_3),向前寻找50像素,满足(overlap_v>0.7)(score)最大的是(box_7),即(j=7)(box_7)反向寻找,满足(overlap_v>0.7)(score)最大的是(box_3),即(k=3)。由于(score_3ge score_3)(pair(box_3,box_7))是最长连接,那么设置(Graph(3,7)=True)
    2. (box_4)正向寻找得到(box_7)(box_7)反向寻找得到(box_3),但是(score_4<score_3),即(pair(box_4,box_7))不是最长连接,包含在(pair(box_3,box_7))中。

    然后,这样就建立了一个(N imes N)的Connect graph(其中(N)是正Anchor数量)。遍历Graph:

    1. (Graph(0,3)=True)(Graph(3,7)=True),所以Anchor index (0 ightarrow 3 ightarrow 7)组成一个文本,即蓝色文本区域。
    2. (Graph(6,10)=True)(Graph(10,12)=True),所以Anchor index (6 ightarrow 10 ightarrow 12)组成另外一个文本,即红色文本区域。

    这样就通过Text proposals确定了文本检测框。

    训练策略

    由于作者没有给出CTPN原始训练代码,所以此处仅能根据论文分析。

    [Loss(s_i,v_i,o_k)=frac{1}{N_s}underset{i}sum L^{cls}_s(s_i,s_i^*)+frac{lambda_1}{N_v}underset{i}sum L_v^{reg}(v_j,v^*_j)+frac{lambda_2}{N_o}underset{k}sum L^{reg}_o(o_k,o^*_k) ]

    明显可以看出,该Loss分为3个部分:

    1. Anchor Softmax loss:该Loss用于监督学习每个Anchor中是否包含文本。(s^*_i={0,1})表示是否是Groud truth。
    2. Anchor y coord regression loss:该Loss用于监督学习每个包含为本的Anchor的Bouding box regression y方向offset,类似于Smooth L1 loss。其中(v_j)(s_i)中判定为有文本的Anchor,或者与Groud truth vertical IoU>0.5。
    3. Anchor x coord regression loss:该Loss用于监督学习每个包含文本的Anchor的Bouding box regression x方向offset,与y方向同理。前两个Loss存在的必要性很明确,但这个Loss有何作用作者没有解释(从训练和测试的实际效果看,作用不大)

    说明一下,在Bounding box regression的训练过程中,其实只需要注意被判定成正的Anchor,不需要去关心杂乱的负Anchor。这与Faster R-CNN类似。

    总结

    1. 由于加入LSTM,所以CTPN对水平文字检测效果超级好。
    2. 因为Anchor设定的原因,CTPN只能检测横向分布的文字,小幅改进加入水平Anchor即可检测竖直文字。但是由于框架限定,对不规则倾斜文字检测效果非常一般。
    3. CTPN加入了双向LSTM学习文字的序列特征,有利于文字检测。但是引入LSTM后,在训练时很容易梯度爆炸,需要小心处理。

    本文来自博客园,作者:甫生,转载请注明原文链接:https://www.cnblogs.com/fusheng-rextimmy/p/15455627.html

  • 相关阅读:
    与红斑痤疮治疗相关的四环素作用
    vue中代码反向代理,从连接本地代理到连接测试服务器
    三元表达式判断数据是否为空后执行内容的 写法
    设计模式
    ASP.NET Core全局异常处理
    前端使用Swiper插件实现用户头像轮播效果
    QT线程、定时器、画家、登录界面代码、QWidget为例
    Leetcode 1248. 统计「优美子数组」(害,突然发现只会暴力枚举了)
    Leetcode 1249. 移除无效的括号(牛逼,终于做出来了)
    Leetcode 1208. 尽可能使字符串相等(终于解决,晚安)
  • 原文地址:https://www.cnblogs.com/fusheng-rextimmy/p/15455627.html
Copyright © 2020-2023  润新知