一文講通OCR文字識別原理與技術全流程(科普版)

語言: CN / TW / HK

theme: condensed-night-purple

我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第3篇文章,點擊查看活動詳情


一、好話説在前頭,誰適合讀本文?

本文的作者在教育行業搞OCR識別工作,教育領域的OCR比較複雜,除了文字外,還有圖片、表格、公式等等。即便同樣是公式,在數學裏要斜體,在化學裏要正體,這都是行業規範。

本文的讀者是誰呢?讀者是……最終誰會讀,我不知道。但是,我定位以下人羣為本文的讀者,換句話説,我就是寫給他們看的。

1.1 公司領導:節省成本,沉澱技術

很多企業領導,看到OCR屬於人工智能範疇,很恐懼。哎呀,我們公司的員工,連正常的業務邏輯都寫不好,交付個系統一堆Bug。

現在需要使用OCR功能了,怎麼辦?買一個吧。不買難道自己做嗎?那樣,我還要建一個人工智能團隊。

這個情況,還真得具體分析。

我瞭解到有一家公司,他們的OCR識別需求非常簡單:僅僅識別0到9,共10個數字。而且,數據來源單一,保證透明背景純色線條字跡。這種待識別的樣本,非常規範

其實,隨便找一本圖像識別的書,翻開第一章,幾乎都是在講如何識別這類數字,這個例題已經20多年了。這在程序員中,被稱為是Hello World級別的程序,是入門的第一課,沒有難度。

甚至谷歌公司覺得這太簡單了,以至於人工智能受到了侮辱。於是,他們率先把入門的例子,由10個數字,改成了識別“輪船”、“汽車”、“青蛙”、“小鳥”等10類物體。

但是,這家公司依然以30萬一年的價格,購買了一個識別數字的OCR服務。

這就像是買了輛大巴車,當電動車來用,一個人開着它走街串巷,維護成本高,利用率也低。

因此,我感覺,領導不需要了解技術細節,但是需要大體瞭解它的成熟度和行業狀態

本文會講述做OCR的流程,以及每一步需要的資源支持,以便領導們可以盤點資源,量入為出。

1.2 產品經理:瞭解過程,融會貫通

產品經理經常被開發人員懟。一方面是開發人員性格過於剛直。另外就是產品經理,有時候確實不瞭解實現過程就亂提需求:比如,App主題色要隨手機殼的顏色來變化。

但是,我也見過那種開發出身的產品經理,他不僅懂產品,也懂技術。

他經常把開發人員懟得一愣一愣的:怎麼實現不了?這邊有數據,那邊也有,做一個關聯,查詢時別不加限制,那樣太慢!

開發人員則紅着臉,遇到新需求時,先自己百度一下,做完了功課再去找這個產品經理辯論。最後,開發人員沮喪着回來,百度也不靠譜啊,原來是有實現思路的!

因此,我感覺產品經理需要了解技術的實現過程,以便在關鍵節點上,可以提出產品側的更優方案

本文會講述實現OCR需要幾個步驟,以及每個步驟的關鍵點是什麼。我覺得產品經理有必要看。

1.3 初級小白:解疑答惑,入門行業

有人覺得OCR好神奇,怎麼做到的?我不明白,誰來給我解釋解釋。這是對此感興趣的求知者。

也有人,非常喜歡圖像識別,自己想學,但是經常會被拒之門外。這是懷有滿腔熱情和憤懣的技術小白。

網絡上,確實有很多大牛,博士碩士研究生,但是因為他們的水平很高,我們很難與他們對話。我曾經被鄙視:一個傅里葉變換,一句話就可以解釋清楚,你卻寫了幾千字,説了一堆廢話。

於是,我認識到“同等對話”很重要。如果我想要實現小康家庭的生活,那我去找全球商業大亨請教,可能起不到什麼效果,反而去跟樓下五金店的老闆拉拉家常,能有所收益。

現在,我弄明白了OCR識別。同時,我也想起之前的迷茫和無助。現在,或許還存在很多曾經的我,我要自己幫一下自己。

本文會講整個OCR的完整流程,以及其中的難點和解決方案(思路以及術語關鍵詞)。如果你是程序員的話,我在專業版裏,還有代碼詳解。

OCR這個行業,如果無法入門,掉頭就走,一旦入門,愛不釋手。

好了,前言我説完了,也算是導讀,如果覺得本文適合你,可以繼續往下看了。

二、OCR識別的全流程(科普版)

OCR是一個簡稱,全稱叫Optical Character Recognition,中文是:光學字符識別。

它的本質是:把圖像形狀轉變為文本字符。

下面説一下,我在教育行業是如何應用OCR的。

信息化教學越來越普及,很多教學素材都要搬到信息化平台,比如試卷試題。那麼,紙質的試卷要電子化,就會用到OCR識別技術。

這麼一張圖,需要識別成結構化(圖片、文字、公式、表格可獨立提取出來)的數據,識別結果如下所示:

而且,識別結果還可以下載成word文檔,便於老師校對並進行二次編輯

這就是OCR的一個典型應用。

除此之外,我們常見的各種證件識別、名片識別、車牌識別等,也涉及OCR技術。

我在入門OCR的時候,做過一個小功能,我把它作為一次學習總結和畢業小考,效果如下:

上面這個例子,在github上已經完全開源。此例子基本囊括了OCR的全過程,下面我就以它作為樣板,來講一講OCR的全流程。

OCR技術的實現,總體上可以分為五步:預處理圖片切割字符識別字符恢復版面後處理文字

中間的三步是核心,頭尾兩步最難。

2.1 預處理圖片

我們買回來水果,需要洗一下再吃。如果運氣不好的話,還需要挖掉蟲眼和糙皮才能吃。我們把吃水果前的這些步驟,叫做CSG(吃水果)的預處理。

在進行OCR之前,也需要對圖片進行預處理。因為,一般待識別的圖片千奇百怪,來源複雜:有拍照、有掃描、有截圖。

拿拍照來説,有夏至那天中午頭兒,在陽光直射下拍的;也有人在傍晚,拿着大頂轉着圈兒拍的。如果不進行預處理,OCR會很為難,就像你面對剛從糞池裏撈上來的大棗一樣為難。

2.1.1 光影的預處理

一般情況下,我們定義白色為背景,黑色為字體。

但是,如果圖片上有了光影,就會存在模糊狀態。説它是背景吧,它不是白色的。要説它是文字吧,黑乎乎地一片兒,也認不出來有什麼字符。這導致OCR經常人格分裂,這是……這不是……它是不是呢?智能出現了問題,人工一看,我給做個預處理吧,交給你的時候保證非黑即白,你專心做事就行。OCR很感動。

2.1.2 傾斜的預處理

理想條件下的文檔圖像,應該是水平的,這樣方便切割方塊字。

但是,現實世界中,不管是人,還是素材,都很難擺正自己的位置。

不正,切起來就複雜了。治圖,如同治人,需要分門別類(強制昇華文章格調)。

上面這種傾斜最為常見,處理起來也最簡單。只需要幾句代碼就能搞定,我會在以後專門介紹。基本原理就是找到文本的最小面積矩形(關鍵詞:minAreaRect),然後旋轉這個矩形,實現角度矯正,看下面這個動態圖。

但是,這種方法有時候也不靈,比如下面這張圖。

我們現在框一個矩形,完美!

我們再把矩形擺正,完蛋!

這種傾斜,無論怎麼擺矩形都不行,因為矩形區域內的文字又有傾斜!

這時候,就需要用另一種方法,叫做霍夫線變換(關鍵詞:HoughLinesP。有時候搜索一個問題,都不知道該搜啥,此處我提供了關鍵詞,其解決方案可直達靈魂)。

霍夫線變換就是在圖上找直線,因為圖中的若干點,是可構成一條直線的。把這些直線畫出來,你會發現玄機,看下面的動態圖。

一段若干行的文本,每一行的字都應該是在一條直線上的。

從結果倒推過程,如果找到了一行直線,那麼是不是就找到了一個文本行。

當把這些直線擺正時,就實現了文檔的矯正。看下面的動態圖。

2.1.3 扭曲的預處理

上面講的是平面的角度傾斜,此類情況在複印和掃描中較多(紙張放斜了)。

這不算嚴重,頂多就如同用涼水泡方便麪,問題不大。

其實,我們遇到更多的圖像是照片。拍照,問題就多了,會存在空間的扭曲。看下面的動態圖(圖是動態的,如果不是,等一等,或者你遇到盜版的作者了,正版作者是ITF男孩)。

上面的圖,問題就比較嚴重了,就如同用煤油泡方便麪,還非得讓別人吃,這叫扭曲。

空間的扭曲,體現在視覺上就是遠大近小。

我們來矯正下面這張圖,這張圖應該是站在長城上拍的長廊,越遠越小。

肯定能矯正,就是步驟有點多。但是,換算成代碼,也不會超過100行。下面這張動態圖裏,我把每一步對圖片處理的方法也都列上了。總共9步,每一步都可以單拉出一篇文章來講解(寫到這裏,我想出視頻教程了,給我點贊,鼓勵我)。

上面的2.1章節部分,講的都是最基礎的預處理操作。

如果你的圖片來源很複雜,尤其是包含各種場景下的拍照,或者也有從漫山遍野撿來的野生圖片、二手改裝圖片。那麼,你的預處理工作將會比較費勁,沒有難點,但是需要耗費人力物力,需要時間

如果,你的圖片來源很簡單。就像我開頭講的,0到9數字識別還購買OCR服務的例子。他們公司是用電子採集筆在電子方格上寫數字,電子方格是統一的,筆是統一的,樣本非常標準。這種情況,不需要預處理,直接進入下一步,切割字符(媽呀,這個轉場,太絲滑了)。

2.2 切割字符

假設,通過了預處理,我們的圖片都變成像下圖這樣規範。

我忽然想到,我們是要做OCR字符識別的(你……幹啥來的)。

於是,我們需要切割字符,把每一個字……都給他(咬着牙,發狠的表情)……挖出來。

為什麼要把每個字符都切割出來?因為OCR最終是對單個字符進行識別的(識別26,其實是識別“2”和“6”)。

並且,還需要對每個字符做好標記,因為識別完了,還得還原回去。識別完了,結果是一堆單蹦的“1”、“2”、“3”、“+”、“-”字符。我們需要根據它們的相對位置,還原成“8-7=1”。所以,我們就知道了,哪個題目做對了,做錯了,從而給出批改結果。

2.2.1 投影法實現分割

上帝説要有光,就有了光。如果有姓尚的朋友,可以給孩子起名叫:尚有光。

有光以後,當光投過來時,物體的背後就有了影。有影子的地方就有實體,沒影子的地方就有空隙。

那位説了(我也不知道哪位),你扯這些幹什麼?這是三歲小孩子都懂的常識。

沒錯,三歲小孩子都知道。但是三十歲的大孩子不一定能想到,這個常識可以用來分割字符。

2.2.2 切行

假設我們拿着一根頭髮絲兒,橫着收集像素點,從左側插入,從右側推出。把所有黑點都壓縮到一起,把黑色素……嗯,黑色素堆到最右側。就像下面的圖這樣。

此時,我們就能清楚地知道哪個區域是有文字的行,哪個區域是白紙。這個價值兩百五的操作,可以實現行的切分

這一招就是投影大法,三歲孩子都瞭解。

2.2.3 切列

切行是橫着切,切列就得豎着切了。

一定要先切行,再切列。多數情況,行是有行距的,每一行都會有明顯的界限。但是列……如果把整個文檔做投影的話,基本上就淪陷了。

上面那樣做投影,拆不出單個字符。因為一篇文檔的字,就像城牆一樣,磨磚對縫,無法切分。

但是,換成對一行文本進行投影分析,就可以了。看下面這個圖,非常之清晰。

通過投影之間的間隙,我們就可以把每個字符切割開來。

2.2.4 切字

有了行與列切分的方法,相信把字符切出來,應該是不難的。其實就是很簡單,代碼也不復雜。全都是數組的分析。

那麼切出來的字,最終是這樣。

不是白紙黑字嗎?為什麼都變成了黑底白字呢?

其實,這是故意的。為的就是要方便OCR進行識別。我們都知道(也可能不知道),在RGB色值中,0代表黑色,255代表白色。

不管計算機的算力多麼強大,一秒鐘能運算多少億萬次,它的底層還是二進制,也就是101010。你可以簡單地理解成它只認識數字。你看到字母A是A,計算機沒有你那麼厲害,計算機偷偷地在顯示器上輸出A這個圖案,然後心裏暗自記下這個物體是65。

因此,任何文本、圖片、音視頻,最終都要被解析成數字,這樣計算機才能幹活。

扯這些有什麼用?你在逃避什麼?黑白顛倒的問題呢?

別急,馬上。我們希望計算機識別圖片上的字,而不是背景。所以,把背景置為黑色,也就0,把字符變成白色,也就是255,這樣有利於計算機更專注於分析字符的痕跡。因為,0默認是忽略掉的。

你看,説着説着,就談到了人工智能的機器學習。哈哈,又轉場了,真爽。

2.3 識別字符

圖片究竟是怎麼變為字符的?它還能自己學習。

計算機通過學習一些樣本之後,遇到一些從未遇到過的同類樣本,也能正確地識別出結果,這很神奇。我想了一夜也沒想明白。

第二天,我帶着孩子去公園,公園門口有一對大獅子。孩子指着獅子説,狗!我説,哦,那不是狗,那是獅子,跟狗有點像是不是。又走了一段路,公園裏又出現一個麒麟的雕塑。孩子指着它説,獅子!我説,那不是獅子。孩子説,是狗。我説也不是狗,它叫:麒麟。我感覺到,孩子的大腦在反向矯正信息,這就是監督學習

當我給他看狗的圖片時,我告訴她這是狗。

她根據自己的認知,找了幾個特徵,構建了一個模型:長嘴+尖牙=狗。

雖然只是看過圖片,但是出門遇到真狗,她根據這個模型也認識對了。

後來,她遇到了獅子,她修改了模型:長嘴+尖牙+鬃毛≠狗=獅子。

後來,又遇到了麒麟,這個公式變得越來越複雜……決策項越來越多。

人工智能,就是模擬的人類的神經元,構建神經網絡來嘗試尋找特徵和結果的關係。如果對了,就給這個特徵加分。如果,錯了,就給這個特徵減分。

識別數字,也是一樣。

比如在學習識別數字6的時候,它隨機認為只要有一個圈圈特徵,就是數字6。

驗證其他樣本時,發現這個隨機特徵是對的(不對就再換一個特徵再試)。於是,它建立了一個模型:只要有圈這個特徵,就是6。

後來,這個模型遇到了數字0。加入新樣本後,人工智能發現,0也有圈,但它不是6,也有可能是0。得再找一個特徵,於是,新增一條,有勾就是6。後來,它又遇到了9。那勾在上面的就是6。後來,它又遇到了字母b……反正計算機有的是算力,能在很短的時間內完成這些學習。上面我是摟着説的,其實即便在32*32像素的小圖片上,它隨機上幾十個特徵去做驗證,一點都不吃力。

這就是識別字符的原理。具體到代碼,也很簡單,因為人工智能框架目前已經非常成熟。雖然,這篇是科普版,不是專業版,不適合講代碼,但是我還是非常想貼上一段代碼,給大家看看。打破你的認知,人工智能的應用層很簡單,別被忽悠了。

舉個例子,識別10類常見物體:飛機、自行車、鳥,貓,鹿、狗、青蛙、馬、輪船、汽車。

它的核心代碼只有……6行。

所以,OCR字符的識別從來不難。難的是兩頭,比如開頭的預處理,以及下面要説的後處理。

2.4 文本後處理

識別出了字符,意義不大,有效地連接起來才能發揮作用。

一定要記住我上面説的這句話,默讀3遍以上。

其實,這句話沒啥用,只是有助於緩解緊張的氣氛!

對於類似的話,我認為是廢話,因為沒有任何指導意義,但是説的也沒錯。

2.4.1 版面還原

可能有人會覺得,我接下來講的會比較跳躍,有點作者着急去廁所的感覺。這並不是什麼寫作風格,這篇文章我快寫吐了,很想快點結束。或許我該搞一個系列專題,我比較喜歡講述體系化的東西,不喜歡一次冒一個點,那樣對別人沒有什麼深度價值。

也可能有人覺得,版面還原不難(是的,進入正題了),字符我都拆開了,座標也記錄了,把識別的字符畫上,不就還原了?!

沒錯,説的很對,把識別的結果畫上去,視覺上是還原了。

但是,這依然屬於單個字符識別的那一步,只不過做成了結果可視化,是座標還原,並不是版面還原。

我們期望的拆分和還原應該是下面這樣:

“10+2= 4-3= 5+6=11”這些文本從數據結構上應該是一行。而且,“10+2=”從數據結構上是一個基本單位。因為,我們要對基本單位做運算和批改。這才叫還原,其實並不簡單。

有點震驚,我拆字的時候,沒有人跟我要求過這些規則。

舉個小例子,這個例子非常小,假設你識別出來了2個字,你現在有2個字符的數據:

請問,這兩個字,是不是在處於同一行?

你通過肉眼無法判定,得計算。

這就需要你用代碼編寫算法處理。如果你數學不好,那可能還真的是一個不小的挑戰。從圖上看,你的眼睛可能幾毫秒就識別出來了,但是計算機沒有眼睛,只有大腦。它就等着你告訴它要怎麼去算什麼數據。

其實也好處理(話都讓你説了,難也是你説的),看兩個字在Y軸的重疊情況。如果重疊達到一定佔比,那就可以認為這兩組數據是處於同一行。

其實字符與字符之間的關係還有很多情況。

根據情況的不同,我們就可以做不同的判定。

上圖所示,如果文本1的矩形區域和公式1的矩形區域,在橫向上有一定比例的重疊,那我們可以認為,它們是處於同一行。如果文本2的區域完全包含(重疊率100%)於表格1的區域中,那麼我們可以認為文本2屬於表格1。同樣,文本2文本3在縱向的重疊率,可以作為它倆是否位於同一列的一個指標。

2.4.2 文本校正

OCR識別的最終目的,是要獲得一份準確的、結構化的文本內容。

單個字符識別,其實是各自為戰,前後不商量。

就比如,遇到一個圓圈形狀的字符圖片。OCR識別就犯了難,它是數字“0”?漢字“〇”?大寫字母“O”?小寫字母“o”?中文句號“。”?還是“Q”忘了加尾巴……。

啥都對,啥都不對。

所以,需要矯正……校正。這兩個詞,都是高頻詞,尤其拼音打字jiaozheng,容易出錯。其實,也好分辨。看語境,如果我前後提到了“文稿”,那麼是“校正”的可能性就大。如果我剛剛説了“牙齒”、“視力”、“角度”啥的,那麼基本上就應該是“矯正”了。

OCR識別的最後一步校正也是一樣。如果無法確定是數字“0”還是字母“o”,可以觀察它相鄰的幾個字符,下面一圖勝千言。

單個字符識別不對沒關係,後期智能校正可以結合語境來幫你糾正。這個步驟就叫做後處理

我想,OCR流程介紹的差不多了。下面該總結了。

三、總結

其實,我已經迫不及待地想睡覺了。但是,睡覺前,我還是想輸出幾個觀點。

3.1 OCR的投入:自己開發 vs 調用第三方?

需要企業領導視自身業務需求和研發能力來確定。

通過上面的流程講解,其實我們也瞭解到,做OCR並不難,這在業界已經非常成熟了。如果,你的業務需求很單一,另外也有一兩個喜歡研究技術的程序員(三年經驗起),其實可以投入幾個人、幾個月搞一搞試試看效果。就算不成功,起碼他們再跟第三方對接起來,也屬於專業級別了。

那麼,如果你的業務需求複雜多樣,是不是就要用第三方服務了。也不一定,需求太複雜,通用的第三方平台,不一定能滿足你的個性化需求。我之前遇到過一個例子,也是在教育行業。他們有一個場景是用在填空題手寫答案上。一般的手寫識別,你就算寫的80%正確,它會給你智能糾正,輸出字符。但是,教育行業不行,寫錯了就是寫錯了,不要糾正。比如,武術的“武”,學生如果右下角寫成了“戈”那樣多了一撇,不要輸出“武”,要輸出不是字,並記錄下學生的錯字圖片。這一下,沒有一家平台可以對接。其實,自己研發是可以做到的。但是,研發這玩意有什麼用?只有自己用。

如果業務比較通用,且第三方費用不是很高的情況下,可以考慮購買服務。其實,不管是個人生活還是企業運轉,總歸都是要考慮成本的控制。最終都是資金限制了一切。所以,我説多少都是白扯。那種説,我有錢,但是找不到人才的老闆,請聯繫我。

3.2 OCR的重點在哪裏?

我認為是數據。

現今而言,瓶頸已經不是技術了,數據量決定識別率。短期內,技術沒有太多可提高的空間了。剩餘的就是拼數據量。

很多人覺得人工智能不智能,甚至智障。其實,有一部分原因就是訓練數據太少。就拿智能問答來説,很多人問的問題,人工智能回答不好。原因就是,你問的這些問題它從來沒有接觸過。

就像我和孩子去公園的例子,我一直給她看狗的圖像,突然問她麒麟是什麼,她會從狗的答案裏去找類似的應對。

我還是拿教育行業舉例(我熟啊),如果我們拿一本魯教版七年級地理上冊,交給人工智能學習。如果它學完了,你問它書本上的知識,它絕對是回答準確。但是,你如果問它七年級下冊的,它估計就蒙了。更何況,還有八年級、九年級呢?更何況學科還有物理、化學、生物呢?更何況,我們生活化的對話場景,不會出現在課本里呢!想讓它聰明,得多少數據,誰又有這些數據?!

OCR也是一樣。識別那一塊兒,大人寫的字和小孩寫的字,是有差別的,想要識別準確,肯定是樣本越多越準確。後處理校正那一塊兒,無他,只能是見多了才能識廣。

3.3 非得湊夠三條嗎?

有人説,你講總結,最好不要超過三條,多了記不住。

但是,如果不夠3條呢?也不用湊。

本文寫了不少。是否對大家有幫助,現在還不好説。這得看大家的反饋了。

我曾經寫過一個Android開發的專欄。

但是,大家對於Android開發其實並不看好,閲讀量少,而且大家也嘲諷現在居然還有人學Android。那我寫這個專欄,其實幫不到很多人。也就是,沒有需求。那我完全可以投入同等精力,去寫另一個受眾更廣的專欄。

對於OCR相關的題材,我有知識儲備,包括github也開源了上面的自動批改項目。至於大家是否有需求,這個是無法預測的。我也會根據文章的閲讀和互動情況,調整後續的內容輸出。

是再出一篇專業版文章,還是出一系列專題,或者是不再更新。也希望大家給我一些反饋。

本文作者掘金@ITF男孩,禁止私自轉載,侵權必究。