ctpn詳解

一.概述

對於複雜場景的文字識別,首先要定位文字的位置,即文字檢測。這一直是一個研究熱點。

文本檢測可以看成特殊的目標檢測,但它有別於通用目標檢測.在通用目標檢測中,每個目標都有定義好的邊界框,檢測出的bbox與當前目標的groundtruth重疊率大於0.5就表示該檢測結果正確.文本檢測中正確檢出需要覆蓋整個文本長度,且評判的標準不同於通用目標檢測,具體的評判方法參見(ICDAR 2017 RobustReading Competition),所以通用的目標檢測方法並不適用文本檢測。

CTPN是在ECCV 2016提出的一種文字檢測算法。CTPN結合CNN與LSTM深度網絡,能有效的檢測出複雜場景的橫向分佈的文字。

二.關鍵idea

  1. 採用垂直anchor迴歸機制,檢測小尺度的文本候選框
  2. 文本檢測的難點在於文本的長度是不固定,可以是很長的文本,也可以是很短的文本.如果採用通用目標檢測的方法,將會面臨一個問題:**如何生成好的text proposal**.針對上述問題,作者提出了一個vertical anchor的方法,具體的做法是隻預測文本的豎直方向上的位置,水平方向的位置不預測。與faster rcnn中的anchor類似,但是不同的是,vertical anchor的寬度都是固定好的了,論文中的大小是16個像素。而高度則從11像素到273像素(每次除以0.7)變化,總共10個anchor.
  3. 採用RNN循環網絡將檢測的小尺度文本進行連接,得到文本行.
  4. 採用CNN+RNN端到端的訓練方式,支持多尺度和多語言,避免後處理                                                                                            

三.ctpn網絡結構

假設輸入N副Images:

  • 首先VGG提取特徵,獲得大小爲conv5 feature map。
  • 之後在conv5上做3*3的滑動窗口,即每個點都結合周圍3*3區域特徵獲得一個長度爲3*3*C的特徵向量。輸出的feature map,該特徵顯然只有CNN學習到的空間特徵。
  • 再將這個feature map進行Reshape:
  • 然後以Batch=NH且最大時間長度T_{max}=W的數據流輸入雙向LSTM,學習每一行的序列特徵。雙向LSTM輸出,再經Reshape恢復形狀:該特徵既包含空間特徵,也包含了LSTM學習到的序列特徵。
  • 然後經過“FC”卷積層,變爲的特徵
  • 最後經過類似Faster R-CNN的RPN網絡,獲得text proposals,如圖2-b。

              

 這裏解釋一下conv5 feature map如何從變爲

                

在原版caffe代碼中是用im2col提取每個點附近的9點臨近點,然後每行都如此處理: 

                                                              

接着每個通道都如此處理:

                                                       

而im2col是用於卷積加速的操作,即將卷積變爲矩陣乘法,從而使用Blas庫快速計算。到了tf,沒有這種操作,所以一般是用conv2d代替im2col,即強行卷積 

接下來,文章圍繞下面三個問題展開:

  1. 爲何使用雙向LSTM
  2. 如何通過FC層輸出產生圖2-b中的Text proposals
  3. 如何通過Text proposals確定最終的文本位置,即文本線構造算法

補充說明:

CTPN的具體實現流程包含三個部分:**檢測小尺度文本框**,**循環連接文本框**,**文本行邊細化**.具體的實現步驟如下:

  1. 使用VGG16作爲base net提取特徵,得到conv5_3的特徵作爲feature map,大小是W×H×C
  2. 在上述的feature map上使用大小爲3*3的滑動窗進行滑動,每個窗口都能得到一個長度爲3×3×C的特徵向量,每個滑動窗口中心都會預測k個相對於anchor的偏移
  3. 將上一步得到的特徵輸入到一個雙向的LSTM中,得到長度爲W×256的輸出,然後接一個512的全連接層,準備輸出。
  4. 輸出層部分主要有三個輸出。2k個vertical coordinate,因爲一個anchor用的是中心位置的高(y座標)和矩形框的高度兩個值表示的,所以一個用2k個輸出。(注意這裏輸出的是相對anchor的偏移)。2k個score,因爲預測了k個text proposal,所以有2k個分數,text和non-text各有一個分數。k個side-refinement,這部分主要是用來精修文本行的兩個端點的,表示的是每個proposal的水平平移量。
  5. 使用一個標準的非極大值抑制算法來濾除多餘的text proposal。
  6. 最後使用基於圖的文本行構造算法,將得到的一個一個的文本段合併成文本行。

 四.雙向LSTM

CNN學習的是感受野內的空間信息,LSTM學習的是序列特徵。對於文本序列檢測,顯然既需要CNN抽象空間特徵,也需要序列特徵(畢竟文字是連續的)。

CTPN中使用雙向LSTM,相比一般單向LSTM有什麼優勢?雙向LSTM實際上就是將2個方向相反的LSTM連起來,如圖r。

                       

一般來說,雙向LSTM都好於單向LSTM。還是看LSTM介紹文章中的例子:

我的手機壞了,我打算____一部新手機。

假設使用LSTM對空白部分填詞。如果只看橫線前面的詞,“手機壞了”,那麼“我”是打算“修”還是“買”還是“大哭一場”?雙向LSTM能看到後面的詞是“一部新手機“,那麼橫線上的詞填“買“的概率就大得多了。顯然對於文字檢測,這種情況也依然適用。

五.全連接層與rpn網絡

經過全連接層得到一個512維的feature map。

                     

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寬高爲:

                               

需要注意,由於CTPN採用VGG16模型提取特徵,那麼conv5 feature map的寬高都是輸入Image的寬高的1/16。

同時fc與conv5 width和height都相等。

如圖6所示,CTPN爲fc feature map每一個點都配備10個上述Anchors。

                                

這樣設置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座標和寬度。具體迴歸方式如下:

                           

(c_y,h)是預測得到的中心座標和高度值,c_y^ah^a是Anchor的中心y座標和高度。(c_y^*,h^*)是Ground Truth的中心座標和高度值。

v=(v_c,v_h)是迴歸預測的值與anchor的座標變換,v=(v_c^{*},v_h^{*})是Ground Truth與anchor的座標變換。

最終需要最小化vv^*的迴歸誤差。可以選用smooth L1損失。

Anchor經過上述Softmax和y方向bounding box regeression處理後,會獲得圖7所示的一組豎直條狀text proposal。後續只需要將這些text proposal用文本線構造算法連接在一起即可獲得文本位置。

                 

在論文中,作者也給出了直接使用Faster R-CNN RPN生成普通proposal與CTPN LSTM+豎直Anchor生成text proposal的對比,如圖8,明顯可以看到CTPN這種方法更適合文字檢測。

 七.文本線構造算法

在上一個步驟中,已經獲得了一串或多串text proposal,接下來就要採用文本線構造辦法,把這些text proposal連接成一個文本檢測框。

                 

爲了說明問題,假設某張圖有圖9所示的2個text proposal,即藍色和紅色2組Anchor,CTPN採用如下算法構造文本線:

  1. 按照水平x座標排序Anchor
  2. 按照規則依次計算每個Anchor box_ipair(box_j),組成pair(x_i,x_j)
  3. 通過pair(x_i,x_j)建立一個Connect graph,最終獲得文本檢測框

下面詳細解釋。假設每個Anchor index如綠色數字,同時每個Anchor Softmax score如黑色數字。

文本線構造算法通過如下方式建立每個Anchor  box_ipair(x_i,x_j)

正向尋找:

  1. 沿水平正方向,尋找和box_i水平距離小於50的候選Anchor
  2. 從候選Anchor中,挑出與box_i豎直方向的Anchor
  3. 挑出符合條件2中Softmax score最大的box_j

再反向尋找:

  1. 沿水平負方向,尋找和box_j水平距離小於50的候選Anchor
  2. 從候選Anchor中,挑出與box_j豎直方向的Anchor
  3. 挑出符合條件2中Softmax score最大的box_k

注:這裏的overlap_v是垂直方向的一維IOU。

最後對比score_iscore_k:

  1. 如果,則這是一個最長連接,那麼設置
  2. 如果,說明這不是一個最長的連接(即該連接肯定包含在另外一個更長的連接中)。

                   

舉例說明,如圖10,Anchor已經按照x順序排列好,並具有圖中的Softmax score(這裏的score是隨便給出的,只用於說明文本線構造算法):

 然後,這樣就建立了一個N \times N的Connect graph(其中N是正Anchor數量)。遍歷Graph:

這樣就通過Text proposals確定了文本檢測框。

八.文本行的side-refinement

因爲這裏規定了迴歸出來的box的寬度是16個像素,所以會導致一些位置上的誤差,這時候就是Side-refinement發揮作用的時候 了。定義的式子如下:

                                           

其中帶*表示爲GroundTruth.。x_{side}表示迴歸出來的左邊界或者右邊界,c_x^a表示anchor中心的橫座標,w_a是固定的寬度16像素。所以O的定義相當於是一個縮放的比例,幫助我們去拉伸回歸之後的box的結果,從而更好地符合實際文本的位置。對比圖如下,紅色框是使用了side-refinement的,而黃色框是沒有使用side-refinement方法的結果:

                                     

 九.Loss 

 loss的表達式如下:preview

CTPN整體包含了3個loss,分類的Ls,邊框迴歸的Lv,邊框左右的迴歸的偏移Lo

Ls爲傳統的softmax_cross_entropy_loss,其中,i表示所有預測的anchor中的第i個,s_i={0,1},Ns爲歸一化參數,表示所有的anchor的總和。

Lv使用的smooth_L1_loss,其中,j表示所有IOU>0.5的anchor中的第j個,Nv爲歸一化參數,表示所有的anchor和groudtruth的IOU>0.5的anchor數總和。λ1爲多任務的平衡參數,λ1=1.0。
Lo也是使用的smooth_L1_loss,其中,k表示邊界anchor中的第k個,即預測和groundtruth相距32個像素的邊界anchor的集合。Nv爲歸一化參數,表示所有邊界anchor數總和。λ1爲多任務的平衡參數,λ1=2.0。

十.代碼分析

 測試和訓練的輸入圖片大小:

測試:

測試的時候和faster的機制一樣,也是短邊大於600,長邊小於1200,這樣的按比例縮放的機制。

def resize_im(im, scale, max_scale=None):
    f=float(scale)/min(im.shape[0], im.shape[1])
    if max_scale!=None and f*max(im.shape[0], im.shape[1])>max_scale:
        f=float(max_scale)/max(im.shape[0], im.shape[1])
    return cv2.resize(im, None,None, fx=f, fy=f,interpolation=cv2.INTER_LINEAR), f

訓練:

訓練的時候,爲了可以走batch,所以是對一個batch內的圖片,取最大的寬,高,其餘小於該寬高的圖片的其他位置補0,這樣進行操作的。

def im_list_to_blob(ims):
    """Convert a list of images into a network input.
    Assumes images are already prepared (means subtracted, BGR order, ...).
    """
    max_shape = np.array([im.shape for im in ims]).max(axis=0)
    num_images = len(ims)
    blob = np.zeros((num_images, max_shape[0], max_shape[1], 3),
                    dtype=np.float32)
    for i in range(num_images):
        im = ims[i]
        blob[i, 0:im.shape[0], 0:im.shape[1], :] = im
 
    return blob

Anchor合併機制:

ctpn需要將每一個anchor迴歸的框進行合併,從而生成最終的文本框。

合併的主要原則,

(1)水平的最大連接距離爲MAX_HORIZONTAL_GAP=50個像素

(2)垂直方向的一維IOU是否滿足大於MIN_V_OVERLAPS=0.7比例

(3)兩個相鄰的anchor的高度是否滿足小於MIN_SIZE_SIM=0.7比例

然後基於上述的原則,首先從左往右掃描一遍,將滿足條件的anchor合併,然後從右往左掃描一遍,將滿足條件的anchor合併。

其中,從左往右掃描的代碼,

    def get_successions(self, index):
        box = self.text_proposals[index]
        results = []
        for left in range(int(box[0]) + 1, min(int(box[0]) + TextLineCfg.MAX_HORIZONTAL_GAP + 1, self.im_size[1])):
            adj_box_indices = self.boxes_table[left]
            for adj_box_index in adj_box_indices:
                if self.meet_v_iou(adj_box_index, index):
                    results.append(adj_box_index)
            if len(results) != 0:
                return results
        return results

從右往左掃描的代碼,

   def get_precursors(self, index):
        box = self.text_proposals[index]
        results = []
        for left in range(int(box[0]) - 1, max(int(box[0] - TextLineCfg.MAX_HORIZONTAL_GAP), 0) - 1, -1):
            adj_box_indices = self.boxes_table[left]
            for adj_box_index in adj_box_indices:
                if self.meet_v_iou(adj_box_index, index):
                    results.append(adj_box_index)
            if len(results) != 0:
                return results
        return results

一維高度IOU的代碼,和高度差距小於0.7的代碼,

def meet_v_iou(self, index1, index2):
        def overlaps_v(index1, index2):
            h1 = self.heights[index1]
            h2 = self.heights[index2]
            y0 = max(self.text_proposals[index2][1], self.text_proposals[index1][1])
            y1 = min(self.text_proposals[index2][3], self.text_proposals[index1][3])
            return max(0, y1 - y0 + 1) / min(h1, h2)
 
        def size_similarity(index1, index2):
            h1 = self.heights[index1]
            h2 = self.heights[index2]
            return min(h1, h2) / max(h1, h2)
 
        return overlaps_v(index1, index2) >= TextLineCfg.MIN_V_OVERLAPS and \
               size_similarity(index1, index2) >= TextLineCfg.MIN_SIZE_SIM

最後附上一段tensorflow版本的ctpn網絡結構代碼,非常清楚明瞭。

def model(image):
    image = mean_image_subtraction(image) # vgg網絡數據預處理,圖像三個通道減去均值
    with slim.arg_scope(vgg.vgg_arg_scope()):
        conv5_3 = vgg.vgg_16(image)

    rpn_conv = slim.conv2d(conv5_3, 512, 3) # 對於vgg16的conv5_3進行3*3的滑動卷積操作

    lstm_output = Bilstm(rpn_conv, 512, 128, 512, scope_name='BiLSTM') # 得到雙向lstm的結果

    bbox_pred = lstm_fc(lstm_output, 512, 10 * 4, scope_name="bbox_pred") # 10*4的bbox的預測值
    cls_pred = lstm_fc(lstm_output, 512, 10 * 2, scope_name="cls_pred") # 10*2的正負anchor分類score
    # transpose: (1, H, W, A x d) -> (1, H, WxA, d)
    cls_pred_shape = tf.shape(cls_pred)
    cls_pred_reshape = tf.reshape(cls_pred, [cls_pred_shape[0], cls_pred_shape[1], -1, 2])

    cls_pred_reshape_shape = tf.shape(cls_pred_reshape)
    cls_prob = tf.reshape(tf.nn.softmax(tf.reshape(cls_pred_reshape, [-1, cls_pred_reshape_shape[3]])),
                          [-1, cls_pred_reshape_shape[1], cls_pred_reshape_shape[2], cls_pred_reshape_shape[3]],
                          name="cls_prob")

    return bbox_pred, cls_pred, cls_prob

十一.總結

優點:

CTPN對於檢測的邊框在上下左右4個點上都比較準確,這點比EAST要好。

缺點:

(1)CTPN只可以檢測水平方向的文本,豎直方向的話就會出現一個字一個字斷開的想象。傾斜角度的話需要修改後處理anchor的連接方式,但是應該會引入新的問題。

(2)CTPN由於涉及到anchor合併的問題,何時合併,何時斷開,這是一個問題。程序使用的是水平50個像素內合併,垂直IOU>0.7合併。或許由於BLSTM的引入,導致斷開這個環節變差。所以對於雙欄,三欄的這種文本,ctpn會都當做一個框處理,有時也會分開處理,總之不像EAST效果好。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章