Cong_Yao_CVPR2017_EAST_An_Efficient_and_Accurate_Scene_Text_Detector
作者和代碼
方法流程
該方法利用多層卷積神經網絡提取圖像特征,再利用該特征分別進行兩個任務,像素點的分類,以及對應像素點的框的回歸。最后將兩個任務結果結合起來,並用非極大值抑制NMS來得到最終檢測結果。
GroundTruth生成
點的分類任務,實際上是一個圖像分割的任務。訓練的時候,文字區域所在部分表示1,非文字的背景部分表示0,這樣就能得到分類任務的groundTruth。為了對邊界像素點可以更好的分類,這個方法對原有的檢測框做了一點收縮,如圖中黃色虛線框收縮成綠色框,這樣邊界像素點可以分類得更准確。
對於框的回歸,首先需要確定的是如何來表示一個框。該方法提出了兩種方式,一種是用四邊形的4個頂點,每個頂點有x和y兩個坐標,故8個坐標來表示,稱為QUAD。這種表示方式模型的學習難度比較大。下面我們詳細解說第二種表示方式RBOX。我們知道,對於任意一個固定點,如果確定該點到四條邊的距離,那么就可以確定一個矩形框。如果再加上角度信息,那么這五個參數d1,d2,d3,d4,以及theta就能唯一確定一個帶角度的矩形框。該方法正是采用這個方式得到框回歸的GroundTruth。比如圖中d圖表示每個點的四個距離,e圖表示對應的angle。
網絡結構
該網絡結構分為三部分,
第一部分是基礎卷積神經網絡模塊,用來提取圖像特征,由PVANet加4個conv stage組成;
第二部分是特征融合模塊,采用類似於FPN的側邊連接方式來逐步將高層特征與低層特征進行融合;
第三部分是預測層,包括三個部分,一個是一通道的分類任務輸出score map,另兩個分別表示檢測框。采用RBOX有5個通道,分別對應我們前面提到的d1,d2,d3,d4和角度theta。采用QUAD則表示采用4個點8個坐標來表示四邊形,有八個通道。
損失函數
安裝
tensorflow(>1.0) + 一些python工具包(requirements.txt)
pip install tensorflow
pip install -r requirements.txt
運行測試Demo
python ./eval.py \
--test_data_path=./test_images/ \
--gpu_list=0 \
--checkpoint_path=./models/ \
--output_dir=./results/
准備訓練數據
訓練流程
- Step1. 准備訓練數據
- Step2. 下載Resnet預訓練模型
- Step3. 修改訓練參數,進行訓練
python multigpu_train.py \
--gpu_list=2,3 \
--input_size=512 \
--batch_size_per_gpu=16 \
--checkpoint_path=./models/ICDAR15_512/ \
--text_scale=512 \
--training_data_path=./datasets/ICDAR15_train/ \
--geometry=RBOX \
--learning_rate=0.0001 \
--num_readers=24 \
--pretrained_model_path=./models/pretrained/resnet_v1_50.ckpt
代碼分析和解讀
關鍵代碼文件說明
文件名 | 文件功能/函數說明 |
---|---|
data_util.py | 訓練數據generator類封裝(與數據並行、多線程相關) |
eval.py | 測試函數 |
model.py | 整個網絡結構搭建、損失函數實現 |
icdar.py | 訓練GroundTruth生成、數據處理、大部分工具函數實現 |
multigpu_train.py | 訓練函數(主要涉及與tf相關的訓練框架) |
nets/ | 包括resnet相關的網絡結構搭建 |
lanms/和local_aware_nms.py | 與NMS相關的python函數、CPP源函數及編譯相關 |
代碼分析和解讀
- model.py( model)
-
model.py (loss)
模型部分,除了結構,損失函數的實現也很重要。分類損失沒有按照論文所說的交叉熵,而是使用了更簡單的dice損失。代碼和公式里的L_AABB是IOU的log損失。這邊兩個矩形框相交面積的計算,沒有采用復雜的計算方式,而是直接用了簡化的近似計算方式。該假設把交集部分近似為一個矩形,然后把點到相對的兩條邊的距離相加來計算矩形的寬和高,並用寬和高直接相乘來算相交面積。這個方法計算簡單,實際是不太精確的,因為相交部分不一定是矩形,有可能是任意四邊形,那么該計算方式就不是非常合理。可以把這部分代碼換成自己的方法實現。
-
icdar.py(generate_rbox)
generate_rbox這個函數,對於整個訓練數據生成非常重要。它的功能是把一個任意四邊形轉成包含四個頂點的最小外接矩形。該方法首先是以四邊形的任意兩個相鄰的邊為基礎,求出包含四個頂點的最小平行四邊形,總共有4個,然后選擇面積最小的平行四邊形,將其轉換為矩形。如圖中所示。灰色是初始的四邊形,紅色為對應的平行四邊形,黃色是最后輸出的矩形。這里的關鍵是第一步如何根據相鄰兩邊來確定平行四邊形。
- 單個平行四邊形生成
這里我們假設要求的是以邊(p0, p1)和邊(p1, p2)作為參考邊的平行四邊形。邊(p0, p1)設為edge,邊(p1, p2)設為forward_edge,邊p0和p3設為backward_edge。首先第一步,先求出點p2和p3到邊edge的距離,求出比較大的那個點,圖中p2距離更遠,因此選擇p2。然后過點p2做一條平行於邊edge的直線,該邊我們定義為edge_opposite。現在,我們就有了平行四邊形的三條邊,接下來了來畫最后一條邊。采用同樣的方法對比點p0和p3到直線forward_edge的距離,選擇距離更遠的點,圖中是p3,然后過點p3做直線平行於forward_edge,最后這條直線稱為forward_opposite。到這里,四條邊都畫出來了,分別是edge,forward_edge,edge_opposite,和forward_opposite,最后根據直線的交點更新4個頂點位置。
-
對應代碼說明
這里點、邊的定義和剛才圖中講解的是一一對應的。Fit_line函數表示根據兩點求直線,point_dist_to_line表示的是點到直線的距離。這個if條件判斷的就是點p2還是p3到邊(p0, p1)的距離哪個更大,然后取更大的點,過該點畫平行直線,即為edge_opposite。
這個介紹的是剛才畫最后一條邊的方法。同樣是判斷點p0和點p3到邊(p1,p2)的距離,取大的那個點,圖中是p3,過p3畫平行於邊(p1,p2)的直線,最后根據直線的交點更新p0和p3,最終新的p0,p1,p2,和p3形成了最后的平行四邊形。
方法亮點
- 提出一種新的框的表示方式(4個d+1個angle),並且對應的IOU Loss和角度的cos Loss
- 屬於一種direct regression,沒有anchor,而且是one-stage的方法,訓練方便
- groundTruth的shrink方式也比較特別,對於邊界像素學習更容易
實驗結果
-
ICDAR2015
-
COCO-Text
- MSRA-TD500
- 速度
總結與收獲
該方法因為比較早“開源”,所以用的人比較多。很多東西比如關於框的表示方式(4個d+1個angle),IOU-Loss以及cos-Loss對后來的方法都有借鑒和參考意義。