EAST演算法超詳細源碼解析:數據預處理與標籤生成

作者簡介

CW,廣東深圳人,畢業於中山大學(SYSU)數據科學與電腦學院,畢業後就業於騰訊電腦系統有限公司技術工程與事業群(TEG)從事Devops工作,期間在AI LAB實習過,實操過道路交通元素與醫療病例影像分割、影片實時人臉檢測與表情識別、OCR等項目。

目前也有在一些自媒體平台上參與外包項目的研發工作,項目專註於CV領域(傳統影像處理與深度學習方向均有)。

前言

EAST: An Efficient and Accurate Scene Text Detector 是用於場景文字識別(OCR)的演算法,五一假期 CW 把這套演算法的源碼研讀了一番,並基於 Pytorch 進行了復現,如今打算把這期間的學習過程記錄下來,本文將對數據處理與標籤生成部分的源碼進行解析,其它部分會在後面的文章中記錄。

01 DataSet 類

在pytorch 中通常會封裝一個類來處理數據集,這個類繼承自 torch.utils.data.DataSet,我們需要重載父類的 ******len **和 getitem 方法。

图片

處理數據集的類 (i)

图片

處理數據集的類 (ii)

图片

處理數據集的類 (iii)

處理數據集的這個類的整體部分如上,接下來就其中的重要部分進行解讀,數據增強的隨機縮放和旋轉這裡就不說了,一起先來看看將影像大小裁剪至512x512這部分。

crop_img:對影像進行隨機起始點的裁剪,裁剪至目標大小512x512

若影像的短邊小於512,則將其放大到512,同時長邊等比例放大。

图片

crop_img(i)

然後對影像中的文本框坐標等比例放大。

图片

crop_img(ii)

接下來就是搜索裁剪方案,搜索的方法是:在影像放大後的尺寸比512x512多出來的空間內進行隨機搜索起始點坐標;一個符合要求的裁剪方案是:裁剪得到的影像不能「分割」了影像中的任一文本框。

图片

crop_img(iii)

【注】以上注釋講解中的「裁剪每一中」字樣去掉

最後,由於影像在放大後進行了裁剪,因此需要將放大後的文本框頂點坐標進行相應的移動。

图片

crop_img(iv)

下一步,我們來看看具體是如何判斷裁剪方案是否符合要求的。

02 is_cross_text:判斷裁剪有無「割裂」影像中的任意文本框

图片

is_cross_text(i)

生成裁剪後影像的多邊形區域以及文本框的多邊形區域,計算兩者的重疊區域面積。

图片

is_cross_text(ii)

計算重疊區域面積占文本框面積的比例,理想情況下是1,因為我們要求文本框完全處於裁剪後影像的內部。注意,只要影像中有任意一個文本框不完全處於裁剪後的影像內部,則該裁剪方案不符合要求!

is_cross_text(iii)

03 get_score_geo: 生成 ground truth

這部分是核心部分,會生成3個map,分別是score map、geo map 以及 ignore map,他們各自的意義已在前面部分解釋。

图片

get_score_geo(i)

以下這部分的處理十分有「藝術」!

首先明確下,這裡製作gt生成的map是在下取樣率為1/4的特徵圖上的,map中的每一點有兩種情況:在文本框內和在文本框外,於是我們要對在文本框內的這些點賦予文本框對應的屬性(score為1,d 和 angle)。

但是,在這裡,作者將我們需要賦值的文本框內點的區域縮小了(將文本框4個頂點向內部移動一定距離,得到一個比文本框面積小的區域),這麼做的原因可能是因為這個map的尺寸是比輸入影像小的,如果和原文本框區域一致,那麼放大回去,有可能會引入文本框邊界以外的點,會引入假正例。

另外,需要注意的是,這裡只是將需要賦值的文本框內的區域縮小,但文本框的坐標本身是沒有改變的!

图片

get_score_geo(ii)

以上還有個處理技巧,就是將文本框旋轉到和水平軸夾角為0的情況(即將斜的框旋轉為正的),這樣對d的計算更加方便。

接下來對旋轉後影像每點(包括在文本框外的)都計算d,d若大於文本框邊長也代表在文本框外,但是由於我們有mask,因此這部分也會被置0。

注意,geo那裡使用的是'+=',是因為影像中可能有多個文本框,而這裡我們計算的是一個文本框。

图片

get_score_geo(iii)

在處理每一個文本框的過程中,記錄了特徵圖中哪些位置該忽略(即不屬於文本框內部),哪些位置該賦值(即處於文本框內部),最後就是將 ignore map 和 score map 分別用這些多邊形填充。

图片

get_score_geo(iv)

下一部分,會對以上談到的那個「藝術」部分進行解讀,看具體是如何將文本框頂點進行內縮的。

04 shrink_poly: 將文本框頂點向內移動,使得文本框區域變小

首先是計算出文本框每個頂點的短邊長度,計算邊長就是計算頂點之間的距離。

图片

shrink_poly(i)

然後判斷下文本框兩對對邊哪一對的長度和更長,先移動長的那一對邊(2條邊,4個頂點)。

图片

shrink_poly(ii)

注意,以上move_points 代表移動一條邊,即2個頂點,返回的是移動後頂點的坐標(包括未移動的),接下來看看具體是如何移動頂點的。

05move_points:將頂點向文本框內部移動

图片

move_points(i)

以下是這部分重點。對於一條邊上的這兩個頂點,分別計算它們各自短邊0.3倍邊長相對於它們組成的這條邊的比例,然後它們的橫縱坐標分別按其對應的這個比例進行移動,兩者移動的方向相反,從而使得兩個頂點會相互靠近。

图片

move_points(ii)

需要注意一點,若這兩個頂點本身距離不超過1,那就不必移動了,因為這說明兩者還未相隔超過1個pixel。

06 find_min_rect_angle:尋找文本框的最小外接矩形,獲得對應的旋轉角度

我們知道,場景文字的方向並不都是水平的,因此文本框與水平軸是有一定角度的,那麼如何知道這個角度是多少呢?

此處是通過枚舉的方式,對於在 [图片] 範圍內的每個角度,都將文本框進行對應的旋轉,旋轉後記錄對應的外接矩形面積,文本框和前10個面積最小的外接矩形的擬合誤差,最終選取誤差最小的那個方案對應的旋轉角。

图片

find_min_rect_angle(i)

图片

find_min_rect_angle(ii)

為了方便理解,CW 特意畫了個圖(雖然很醜哈哈哈):

图片

文本框旋轉,與外接矩形的擬合誤差

如上圖,v1、v2、v3、v4是文本框4個頂點,文本框與水平軸的真實夾角是图片,假設我們在枚舉過程中遇到一角度图片,然後將文本框進行對應旋轉,旋轉後的外接矩形就是上圖右上部分的ABCD,陰影部分就是外接矩形比文本框多出來的面積。

我們可以認為,這個面積越小則外接矩形與文本框越相近,誤差也越小,因此我們選取面積最小的前10個外接矩形道理就在於此。

理想情況下,我們找到了真實的角度图片,這時候旋轉文本框,得到的外接矩形就會和文本框重合(當然,文本框不是直角矩形而是其它多邊形形狀時,不會重合),如上圖中間部分,這時候外接矩形的面積最小,擬合誤差最小。

07cal_error:計算文本框與外接矩形的擬合誤差

由上一部分我們知道,擬合誤差與外接矩形面積有正相關關係,現在就來看看這個誤差值具體是通過什麼來計算的。

图片

cal_error

上圖程式碼應該交代的很明白了,擬合誤差實質就是文本框與外接矩形4個頂點之間對應距離之和。

08 rotate_all_pixels: 旋轉影像中的所有點

最後來看看影像中的點是如何旋轉的。

图片

rotate_all_pixels(i)

图片

rotate_all_pixels(ii)

以上的rotate_mat是旋轉操作對應的仿射變換矩陣,根據旋轉角即可計算獲得:

图片

get_rotate_mat

09 結語

數據預處理與標籤生成的源碼解析就到此為止了,CW通過程式碼了解到,這裡面還是有不少trick的,從而感受到作者在其中加入了很多對生活實際情況的思考。由此可知,作為技術工程師,必須多多觀察與思考,在生活中汲取靈感,這樣才能真正創造出實用有效的東西。