OCR光学字符识别
OCR光學字符識別 – 潘登同學的NLP筆記
文章目錄
- OCR光學字符識別 -- 潘登同學的NLP筆記
- 傳統的OCR方法
- 文字行提取
- 基于切分的方法
- 不依賴切分的方法
- 深度學習的方法
- 受控場景的文字檢測
- 非受控場景的文字檢測
- 基于序列學習的文字識別
- CTC Loss
- 數學表達
傳統的OCR方法
OCR (Optical Character Recognition,光學字符識別)是指電子設備(例如掃描儀或數碼相機)檢查紙上打印的字符,通過檢測暗、亮的模式確定其形狀,然后用字符識別方法將形狀翻譯成計算機文字的過程;即,針對印刷體字符,采用光學的方式將紙質文檔中的文字轉換成為黑白點陣的圖像文件,并通過識別軟件將圖像中的文字轉換成文本格式;
一個OCR識別系統,其目的很簡單,只是要把影像作一個轉換,使影像內的圖形繼續保存、有表格則表格內資料及影像內的文字,一律變成計算機文字,使能達到影像資料的儲存量減少、識別出的文字可再使用及分析,當然也可節省因鍵盤輸入的人力與時間。
從影像到結果輸出,須經過影像輸入、影像前處理、文字特征抽取、比對識別、最后經人工校正將認錯的文字更正,將結果輸出。
傳統步驟
- 輸入圖像預處理
- 二值化:我們需要先對彩色圖進行處理,使圖片只前景信息與背景信息,可以簡單的定義前景信息為黑色,背景信息為白色,這就是二值化圖了;
- 噪聲去除:對于不同的文檔,我們對噪聲的定義可以不同,根據噪聲的特征進行去噪;
- 傾斜較正:由于一般用戶,在拍照文檔時,都比較隨意,因此拍照出來的圖片不可避免的產生傾斜,這就需要文字識別軟件進行較正;
- 識別過程
- 版面分析:將文檔圖片分段落,分行的過程就叫做版面分析,由于實際文檔的多樣性,復雜性,因此,目前還沒有一個固定的,最優的切割模型;
- 字符切割:由于拍照條件的限制,經常造成字符粘連,斷筆,因此極大限制了識別系統的性能,這就需要文字識別軟件有字符切割功能;
- 字符識別:這一研究,已經是很早的事情了,比較早有模板匹配,后來以特征提取為主,由于文字的位移,筆畫的粗細,斷筆,粘連,旋轉等因素的影響,極大影響特征的提取的難度;
- 后處理
- 版面恢復:人們希望識別后的文字,仍然像原文檔圖片那樣排列著,段落不變,位置不變,順序不變地輸出到word文檔、pdf文檔等,這一過程就叫做版面恢復;
- 后處理、校對:根據特定的語言上下文的關系,對識別結果進行較正,就是后處理;
傳統的OCR基于圖像處理(二值化、連通域分析、投影分析等)和統計機器學習(Adaboost、SVM),過去20年間在印刷體和掃描文檔上取得了不錯的效果。傳統的印刷體OCR解決方案整體流程如圖所示。
傳統的OCR解決方案存在著以下不足:
- 通過版面分析(連通域分析)和行切分(投影分析)來生成文本行,要求版面結構有較強的規則性且前背景可分性強(例如黑白文檔圖像、車牌),無法處理前背景復雜的隨意文字(例如場景文字、菜單、廣告文字等)。另外,二值化操作本身對圖像成像條件和背景要求比較苛刻。
- 通過人工設計邊緣方向特征(例如方向梯度直方圖)來訓練字符識別模型,在字體變化、模糊或背景干擾時,此類單一的特征的泛化能力迅速下降。
- 過度依賴于字符切分的結果,在字符扭曲、粘連、噪聲干擾的情況下,切分的錯誤傳播尤其突出。
- 盡管圖像預處理模塊可有效改善輸入圖像的質量,但多個獨立的校正模塊的串聯必然帶來誤差傳遞。另外由于各模塊優化目標獨立,它們無法融合到統一的框架中進行。
行切分,投影切分例子
輸入圖片
二值圖片
水平投影
行切分
文字行提取
傳統OCR采取自上而下的切分式,但它只適用于版面規則背景簡單的情況。該領域還有另外兩類思路
- 自底向上的生成式方法。該類方法通過連通域分析或最大穩定極值區域(MSER)等方法提取候選區域,然后通過文字/非文字的分類器進行區域篩選,對篩選后的區域進行合并生成文字行,再進行文字行級別的過濾,如圖所示。該類方法的不足是,一方面流程冗長導致的超參數過多,另一方面無法利用全局信息
- 基于滑動窗口的方法。該類方法利用通用目標檢測的思路來提取文字行信息,利用訓練得到的文字行/詞語/字符級別的分類器來進行全圖搜索。原始的基于滑動窗口方法通過訓練文字/背景二分類檢測器,直接對輸入圖像進行多尺度的窗口掃描。檢測器可以是傳統機器學習模型(Adaboost、Random Ferns),也可以是深度卷積神經網絡
文字行識別流程
傳統OCR將文字行識別劃分為字符切分和單字符識別兩個獨立的步驟,盡管通過訓練基于卷積神經網絡的單字符識別引擎可以有效提升字符識別率,但切分對于字符粘連、模糊和形變的情況的容錯性較差,而且切分錯誤對于識別是不可修復的。因此在該框架下,文本行識別的準確率主要受限于字符切分。假設已訓練單字符識別引擎的準確率p=99%,字符切分準確率為q= 95%,則對于一段長度為L的文字行,其識別的平均準確率為P= (pq)的L次方,其中L=10時,P=54.1%
由于獨立優化字符切分提升空間有限,因此有相關方法試圖聯合優化切分和識別兩個任務。現有技術主要可分為基于切分的方法(Segmentation-Based)和不依賴切分的方法(Segmentation- Free)兩類方法。
基于切分的方法
該類方法還是保留主動切分的步驟,但引入了動態合并機制,通過識別置信度等信息來指導切分,如圖所示。
- 過切分模塊將文字行在垂直于基線方向上分割成碎片,使得其中每個碎片至多包含一個字符。通常來說,過切分模塊會將字符分割為多個連續筆劃。過切分可以采用基于規則或機器學習的方法。規則方法主要是直接在圖像二值化的結果上進行連通域分析和投影分析來確定候補切點位置,通過調整參數可以控制粒度來使得字符盡可能被切碎。基于規則的方法實現簡單,但在成像/背景復雜的條件下其效果不好。機器學習方法通過離線訓練鑒別切點的二類分類器,然后基于該分類器在文字行圖像上進行滑窗檢測
- 動態合并模塊將相鄰的筆劃根據識別結果組合成可能的字符區域,最優組合方式即對應最佳切分路徑和識別結果。直觀來看,尋找最優組合方式可轉換為路徑搜索問題,對應有深度優先和廣度優先兩種搜索策略。深度優先策略在每一步選擇擴展當前最優的狀態,因此全局來看它是次優策略,不適合過長的文字行。廣度優先策略在每一步會對當前多個狀態同時進行擴展,比如在語音識別領域廣泛應用的Viterbi解碼和Beam Search。但考慮到性能,Beam Search通常會引入剪枝操作來控制路徑長度,剪枝策略包含限制擴展的狀態數(比如,每一步只擴展TopN的狀態)和加入狀態約束(比如,合并后字符形狀)等;
- 由于動態合并會產生多個候選路徑,所以需要設計合適的評價函數來進行路徑選擇。評價函數的設計主要從路徑結構損失和路徑識別打分兩方面出發。路徑結構損失主要從字符形狀特征方面衡量切分路徑的合理性,路徑識別打分則對應于特定切分路徑下的單字平均識別置信度和語言模型分。
- 該方案試圖將字符切分和單字符識別融合在同一個框架下解決,但由于過分割是獨立的步驟,因此沒有從本質上實現端到端學習;
不依賴切分的方法
該類方法完全跨越了字符切分,通過滑動窗口或序列建模直接對文字行進行識別
滑窗識別借鑒了滑動窗口檢測的思路,基于離線訓練的單字識別引擎,對文字行圖像從左到右進行多尺度掃描,以特定窗口為中心進行識別。在路徑決策上可采用貪心策略或非極大值抑制(NMS)策略來得到最終的識別路徑。下圖給出了滑窗識別的示意流程。可見滑窗識別存在兩個問題:滑動步長的粒度過細則計算代價大,過粗則上下文信息易丟失;無論采用何種路徑決策方案,它們對單字識別的置信度依賴較高。
序列學習起源于手寫識別、語音識別領域,因為這類問題的共同特點是需要對時序數據進行建模。盡管文字行圖像是二維的,但如果把從左到右的掃描動作類比為時序,文字行識別從本質上也可歸為這類問題。通過端到端的學習,摒棄矯正/切分/字符識別等中間步驟,以此提升序列學習的效果,這已經成為當前研究的熱點;(深度學習的方法)
深度學習的方法
深度學習的方法可以歸結為兩步
- 目標檢查
- 文字識別
根據版面是否有先驗信息(卡片的矩形區域、證件的關鍵字段標識)以及文字自身的復雜性(如水平文字、多角度),圖像可劃分為受控場景(如身份證、營業執照、銀行卡)和非受控場景(如菜單、門頭圖),如圖所示
考慮到這兩類場景的特點不同,我們借鑒不同的檢測框架。由于受控場景文字諸多約束條件可將問題簡化,因此利用在通用目標檢測領域廣泛應用的Faster R-CNN框架進行檢測。而對于非受控場景文字,由于形變和筆畫寬度不一致等原因,目標輪廓不具備良好的閉合邊界,我們需要借助圖像語義分割來標記文字區域與背景區域。
受控場景的文字檢測
對于受控場景(如身份證),我們將文字檢測轉換為對關鍵字目標(如姓名、身份證號、地址)或關鍵條目(如銀行卡號)的檢測問題。基于Faster R-CNN的關鍵字檢測流程如圖所示。為了保證回歸框的定位精度,同時提升運算速度,我們對原有框架和訓練方式進行了微調
- 考慮到關鍵字或關鍵條目的類內變化有限,網絡結構只采用了3個卷積層
- 訓練過程中提高正樣本的重疊率(IOU)閾值
- 根據關鍵字或關鍵條目的寬高比范圍來適配RPN層Anchor的寬高比
Faster R-CNN框架由RPN(候選區域生成網絡)和RCN(區域分類網絡)兩個子網絡組成。RPN通過監督學習的方法提取候選區域,給出的是無標簽的區域和粗定位結果。RCN引入類別概念,同時進行候選區域的分類和位置回歸,給出精細定位結果。訓練時兩個子網絡通過端到端的方式聯合優化。下圖以銀行卡卡號識別為例,給出了RPN層和RCN層的輸出
對于人手持證件場景,由于證件目標在圖像中所占比例過小,直接提取微小候選目標會導致一定的定位精度損失。為了保證高召回和高定位精度,可采用由粗到精的策略進行檢測。首先定位卡片所在區域位置,然后在卡片區域范圍內進行關鍵字檢測,而區域定位也可采用Faster R-CNN框架,如圖所示。
非受控場景的文字檢測
對于菜單、門頭圖等非受控場景,由于文字行本身的多角度且字符的筆畫寬度變化大,該場景下的文字行定位任務挑戰很大。由于通用目標檢測方法的定位粒度是回歸框級,此方法適用于剛體這類有良好閉合邊界的物體。然而文字往往由一系列松散的筆畫構成,尤其對于任意方向或筆畫寬度的文字,僅以回歸框結果作為定位結果會有較大偏差。另外剛體檢測的要求相對較低,即便只定位到部分主體(如定位結果與真值的重疊率是50%),也不會對剛體識別產生重大影響,而這樣的定位誤差對于文字識別則很可能是致命的。
為了實現足夠精細的定位,我們利用語義分割中常用的全卷積網絡(FCN)來進行像素級別的文字/背景標注,整體流程如圖所示
多尺度全卷積網絡通過對多個階段的反卷積結果的融合,實現了全局特征和局部特征的聯合,進而達到了由粗到精的像素級別標注,適應于任意非受控場景(門頭圖、菜單圖片);
基于多尺度全卷積網絡得到的像素級標注,通過連通域分析技術可得到一系列連通區域(筆劃信息)。但由于無法確定哪些連通域屬于同一文字行,因此需要借助單鏈聚類技術來進行文字行提取。至于聚類涉及的距離度量,主要從連通域間的距離、形狀、顏色的相似度等方面提取特征,并通過度量學習自適應地得到特征權重和閾值,如圖所示
基于序列學習的文字識別
我們將整行文字識別問題歸結為一個序列學習問題。利用基于雙向長短期記憶神經網絡(Bi-directional Long Short-term Memory,BLSTM)的遞歸神經網絡作為序列學習器,來有效建模序列內部關系。為了引入更有效的輸入特征,我們采用卷積神經網絡模型來進行特征提取,以描述圖像的高層語義。此外在損失函數的設計方面,考慮到輸出序列與輸入特征幀序列無法對齊,我們直接使用結構化的Loss(序列對序列的損失),另外引入了背景(Blank)類別以吸收相鄰字符的混淆性。
整體網絡結構分為三層:卷積層、遞歸層和翻譯層,如圖所示。其中卷積層提取特征;遞歸層既學習特征序列中字符特征的先后關系,又學習字符的先后關系;翻譯層實現對時間序列分類結果的解碼.
對于輸入的固定高度h0= 36的圖像(寬度任意,如W0 = 248),我們通過CNN網絡結構提取特征,得到9×62×128的特征圖,可將其看作一個長度為62的時間序列輸入到RNN層。RNN層有400個隱藏節點,其中每個隱藏節點的輸入是9×128維的特征,是對圖像局部區域的描述。考慮到對應于某個時刻特征的圖像區域,它與其前后內容都具有較強的相關性,所以我們一般采用雙向RNN網絡,如圖所示
而這個圖中核心的就是bilstm的輸出除了普通的字符之外,還有_來表示空白區域,兩個_之間重復出現的往往需要被過濾器合并,滿足過濾器前的所有正樣本有很多種,總的來說,就是一個類似曼哈頓道路的序列路徑(類似,但絕對不是) 總之,生成這樣的道路可以根據規則生成,而在計算關鍵的CTC loss的時候,往往采用的是動態規劃的思想進行計算
雙向RNN后接一個全連接層,輸入為RNN層(在某個時刻)輸出的特征圖,輸出為該位置是背景、字符表中文字的概率。全連接層后接CTC(聯結主義時間分類器)作為損失函數。在訓練時,根據每個時刻對應的文字、背景概率分布,得到真值字符串在圖像中出現的概率P(ground truth),將-log(P(ground truth))作為損失函數。在測試時,CTC可以看作一個解碼器,將每一時刻的預測結果(當前時刻的最大后驗概率對應的字符)聯合起來,然后去掉空白和重復的模式,就形成了最終的序列預測結果,如圖所示
從上圖中也可以看出,對應輸入序列中的每個字符,LSTM輸出層都會產生明顯的尖峰,盡管該尖峰未必對應字符的中心位置。換句話說,引入CTC機制后,我們不需要考慮每個字符出現的具體位置,只需關注整個圖像序列對應的文字內容,最終實現深度學習的端到端訓練與預測。
基于上述序列學習框架,我們給出了在不同場景下的文字行識別結果,如圖18所示。其中前兩行的圖片為驗證碼場景,第三行為銀行卡,第四行為資質證件,第五行為門頭圖,第六行為菜單。可以看到,識別模型對于文字形變、粘連、成像的模糊和光線變化、背景的復雜等都有較好的健壯性。
CTC Loss
舉個例子
- 如果我們的標簽序列,就是真實的數據“水煮肉片22元”,長度設為L,加入blank空格之后,長度為多少?
“_水_煮_肉_片_2_2_元_”
2*L+1
-
最終將預測的序列:
- 連續相同的字符去重!
- 去除空字符!
-
所以我們要想我們的預測序列可以經過上述的去重去空格得到正確答案,所以我們是不是在訓練模型的時候,就要給RNN準備各種可能的路徑~
各種可能的路徑是不是要根據之前的“_水_煮_肉_片_2_2_元_”來構建
- 為了最終去重去空格可以不會錯,那么我們在構建各種可能的路徑時候就需要加入一些約束條件!
- 方向只能向下和向右(向下其實是指斜向下)
- 相同的字符之間要有一個空字符(這是指22這個中間必須要有一個_,而不是不能出現‘22_2’這種情形)
- 非空字符不能被跳過(不能少字)
- 起點必須從前兩個字符開始
- 終點必須在結尾兩個字符結束
CTC Loss求解的是所有可能路徑的對數概率之和最大,用到動態規劃的思想;動態規劃需要初始條件和狀態轉移方程
符號記法s表示狀態(字符),t表示時刻,f表示狀態概率函數, p表示該狀態的輸出概率(bilstm的輸出概率)
- 情況一: 第s個字符是blank(因為上一個blank后面不能跨過字符接blank)
ft(s)=(ft?1(s)+ft?1(s?1))?p(s)f_t(s) = (f_{t-1}(s) + f_{t-1}(s-1)) * p(s) ft?(s)=(ft?1?(s)+ft?1?(s?1))?p(s) - 情況二:第s個字符和第s-2個字符相同(因為兩個相同字符間必須接blank)
ft(s)=(ft?1(s)+ft?1(s?1))?p(s)f_t(s) = (f_{t-1}(s) + f_{t-1}(s-1)) * p(s) ft?(s)=(ft?1?(s)+ft?1?(s?1))?p(s) - 其他情況
ft(s)=(ft?1(s)+ft?1(s?1)+ft?1(s?2))?p(s)f_t(s) = (f_{t-1}(s) + f_{t-1}(s-1) + f_{t-1}(s-2)) * p(s) ft?(s)=(ft?1?(s)+ft?1?(s?1)+ft?1?(s?2))?p(s)
最后把fT(S)f_T(S)fT?(S)和fT(S?1)f_T(S-1)fT?(S?1)的和最大化即可
CTC算法特性
-
條件獨立性,CTC loss最開始是用在語言識別的,后來才用于OCR
-
比如一個人去說“三個A”,輸出有兩個,AAA,triple A; 它不會學到任何語言模型的知識,更像n-gram的統計語言模型
-
CTC算法不需要訓練數據對齊(給規則即可)
-
CTC要求對齊的方式是單調的(水煮肉片 22元與22元 水煮肉片是不同的),像機器翻譯的任務就不適合用CTC Loss
-
CTC要求輸入和輸出是多對一的關系,有的任務是需要嚴格一對一關系,比如詞性標注也不適合用CTC Loss
-
CTC要求輸出要比輸入短(如63個時刻,7個輸出)
數學表達
LCTC(X,W)=?log?∑C:K(C)=Wp(C∣X)=?log?∑C:K(C)=W∏t=1Tp(ct∣X)\begin{aligned} L_{CTC}(X,W) &= -\log \sum_{C:K(C)=W}p(C|X) \\ &= -\log \sum_{C:K(C)=W}\prod_{t=1}^Tp(c_t|X) \end{aligned} LCTC?(X,W)?=?logC:K(C)=W∑?p(C∣X)=?logC:K(C)=W∑?t=1∏T?p(ct?∣X)?
其中,WWW表示滿足條件的所有序列形式,T表示時刻數,p(ct∣X)p(c_t|X)p(ct?∣X)則是LSTM給出的概率值
除此之外,還有一種表示所有路徑可能的形式
- αt(s)\alpha_t(s)αt?(s)表示從開始到時刻t,狀態s的所有路徑的概率
αt(s)=∑π∈K(π1:t)=l1:s∏t′=1tyπt′t′\alpha_t(s) = \sum_{\pi \in K(\pi_{1:t})=l_{1:s}} \prod_{t'=1}^ty_{\pi_t'}^{t'} αt?(s)=π∈K(π1:t?)=l1:s?∑?t′=1∏t?yπt′?t′? - βt(s)\beta_t(s)βt?(s)表示從時刻t,狀態s到結束的所有路徑的概率
βt(s)=∑π∈K(πt:T)=ls:∣l∣∏t′=1tyπt′t′\beta_t(s) = \sum_{\pi \in K(\pi_{t:T})=l_{s:|l|}} \prod_{t'=1}^ty_{\pi_t'}^{t'} βt?(s)=π∈K(πt:T?)=ls:∣l∣?∑?t′=1∏t?yπt′?t′?
很容易證明
αt(s)βt(s)yst=∑π∈K?1(l):πt=syst∏t=1Tyπttylst=∑π∈K?1(l):πt=s∏t=1Tyπtt\frac{\alpha_t(s)\beta_t(s)}{y_{s}^t} = \frac{\sum_{\pi\in K^{-1}(l): \pi_t=s} y_{s}^t \prod_{t=1}^Ty_{\pi_t}^t}{y_{l_s}^t} = \sum_{\pi\in K^{-1}(l): \pi_t=s} \prod_{t=1}^Ty_{\pi_t}^t yst?αt?(s)βt?(s)?=yls?t?∑π∈K?1(l):πt?=s?yst?∏t=1T?yπt?t??=π∈K?1(l):πt?=s∑?t=1∏T?yπt?t?
p(l∣x)=∑π∈K?1(l)p(π∣x)=∑π∈K?1(l)∏t=1Tyπtt=∑π∈K?1(l):πt=sαt(s)βt(s)yπttp(l|x) = \sum_{\pi\in K^{-1}(l)} p(\pi|x) = \sum_{\pi\in K^{-1}(l)} \prod_{t=1}^Ty_{\pi_t}^t = \sum_{\pi\in K^{-1}(l): \pi_t=s}\frac{\alpha_t(s)\beta_t(s)}{y_{\pi_t}^t} p(l∣x)=π∈K?1(l)∑?p(π∣x)=π∈K?1(l)∑?t=1∏T?yπt?t?=π∈K?1(l):πt?=s∑?yπt?t?αt?(s)βt?(s)?
p(l∣x)p(l|x)p(l∣x)可以理解為所有路徑之和
現在我們要做的事情就是:通過梯度?p(l∣x)?ytk\frac{\partial{p(l|x)}}{\partial{y_t^k}}?ytk??p(l∣x)?調整LSTM的參數w,使得對于輸入樣本為x∈K?1(z)x\in K^{-1}(z)x∈K?1(z)時有 p(l∣x)p(l|x)p(l∣x) 取得最大。所以如何計算梯度才是核心
?p(l∣x)?ytk=?∑π∈K?1(l):πt=sαt(s)βt(s)yπtt?ytk=?∑π∈K?1(l):πt=sαt(s)βt(s)yπtt(ytk)?2\frac{\partial{p(l|x)}}{\partial{y_t^k}} = \frac{\partial{\sum_{\pi\in K^{-1}(l): \pi_t=s}\frac{\alpha_t(s)\beta_t(s)}{y_{\pi_t}^t}}}{\partial{y_t^k}} = -\frac{{\sum_{\pi\in K^{-1}(l): \pi_t=s}\frac{\alpha_t(s)\beta_t(s)}{y_{\pi_t}^t}}}{{(y_t^k)^{-2}}} ?ytk??p(l∣x)?=?ytk??∑π∈K?1(l):πt?=s?yπt?t?αt?(s)βt?(s)??=?(ytk?)?2∑π∈K?1(l):πt?=s?yπt?t?αt?(s)βt?(s)??
注意 這些符號記法不是關鍵,核心就是動態規劃的思想,只要能推出完整的動規路徑,就很容易去追蹤導數…
總結
- 上一篇: 大数据与网络科学
- 下一篇: 在wordpress添加自制html页面