天天看點

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詳解

三.ctpn網絡結構

假設輸入N副Images:

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

 這裡解釋一下conv5 feature map如何從

ctpn詳解

變為

ctpn詳解
ctpn詳解

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

ctpn詳解

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

ctpn詳解

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

ctpn詳解

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

  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。

ctpn詳解

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

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

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

五.全連接配接層與rpn網絡

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

ctpn詳解

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詳解

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

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

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

ctpn詳解

這樣設定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坐标和寬度。具體回歸方式如下:

ctpn詳解
ctpn詳解

是預測得到的中心坐标和高度值,

ctpn詳解

ctpn詳解

是Anchor的中心y坐标和高度。

ctpn詳解

是Ground Truth的中心坐标和高度值。

ctpn詳解

是回歸預測的值與anchor的坐标變換,

ctpn詳解

是Ground Truth與anchor的坐标變換。

最終需要最小化

ctpn詳解

ctpn詳解

的回歸誤差。可以選用smooth L1損失。

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

ctpn詳解

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

ctpn詳解

 七.文本線構造算法

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

ctpn詳解

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

  1. 按照水準x坐标排序Anchor
  2. 按照規則依次計算每個Anchor 
    ctpn詳解
    ctpn詳解
    ,組成
    ctpn詳解
  3. 通過
    ctpn詳解
    建立一個Connect graph,最終獲得文本檢測框

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

文本線構造算法通過如下方式建立每個Anchor  

ctpn詳解

ctpn詳解

正向尋找:

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

再反向尋找:

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

注:這裡的

ctpn詳解

是垂直方向的一維IOU。

最後對比

ctpn詳解

ctpn詳解

:

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

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

ctpn詳解

 然後,這樣就建立了一個

ctpn詳解

的Connect graph(其中N是正Anchor數量)。周遊Graph:

ctpn詳解

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

八.文本行的side-refinement

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

ctpn詳解

其中帶*表示為GroundTruth.。

ctpn詳解

表示回歸出來的左邊界或者右邊界,

ctpn詳解

表示anchor中心的橫坐标,

ctpn詳解

是固定的寬度16像素。是以O的定義相當于是一個縮放的比例,幫助我們去拉伸回歸之後的box的結果,進而更好地符合實際文本的位置。對比圖如下,紅色框是使用了side-refinement的,而黃色框是沒有使用side-refinement方法的結果:

ctpn詳解

 九.Loss 

 loss的表達式如下:

ctpn詳解
ctpn詳解

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

Ls為傳統的softmax_cross_entropy_loss,其中,i表示所有預測的anchor中的第i個,

ctpn詳解

,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效果好。

繼續閱讀