天天看點

一文解讀光學字元識别(OCR)與手寫文本識别(HTR)

選自Medium

作者:Ajinkya Khalwadekar

機器之心編譯參與:Panda、蛋醬

在機器學習和計算機視覺領域,光學字元識别(OCR)和手寫文本識别(HTR)長期以來都是人們研究的重要主題。本文将幫助計算機視覺愛好者大緻了解如何對文檔圖像中的文本進行識别。

光學字元識别和手寫文本識别是人工智能領域裡非常經典的問題。OCR 很簡單,就是将文檔照片或場景照片轉換為機器編碼的文本;而 HTR 就是對手寫文本進行同樣的操作。作者在文章中将這個問題分解成了一組更小型的問題,并制作了如下的流程圖。

一文解讀光學字元識别(OCR)與手寫文本識别(HTR)

圖 1.1:應用流程圖 按文檔邊框裁剪圖像 在圖像進行中,通常需要對圖像進行預先編輯,以便獲得更好的表征。裁剪是圖像編輯中最常用的操作之一,這可以移除圖像中不需要的部分,也可以向圖像添加所需的特征。

你可以使用 OpenCV 來輕松地找到圖像中文檔的邊緣,查找圖像中文檔邊緣的最佳方法是使用門檻值圖像。OpenCV 提供了不同的門檻值樣式,這是由其函數的第 4 個參數決定的。在這個函數中,第一個參數是源圖像,這應該是一張灰階圖像;第二個參數是用于分類像素值的門檻值;第三個參數是 maxVal,這是當像素值超過(有時是低于)門檻值時所要給出的值。下面的代碼将能幫助你找到門檻值圖像,然後确定文檔邊緣的輪廓,你可以将這些輪廓點與圖像邊緣進行比較,然後确定文檔的邊緣。

# threshold image
ret, thresh = cv2.threshold(imgray, 150, 255, 0)
cv2.imwrite('thresh.jpg', thresh)
# edge contours
contours, hierarchy = cv2.findContours(thresh, 1, 2)           

檢測和裁剪/分割文檔中的所有詞 在有限制的受控環境中進行詞檢測通常可以使用啟發式方法實作,比如利用梯度資訊或者這樣的事實:文本通常會被分組成段落以及排列成直線的字元。但是,使用啟發式方法是存在缺陷的,圖像中很多不需要的區域也會被檢測為詞,是以我們可以使用 OpenCV 的 EAST(Efficient and Accurate Scene Text)檢測器。可以參考 Adrian Rosebrock 寫的 EAST 檢測器相關文章:https://www.pyimagesearch.com/2018/08/20/opencv-text-detection-east-text-detector/ 然後再根據 Tom Hoag 分享的方法對其進行改進:https://medium.com/@tomhoag/opencv-text-detection-548950e3494c這種方法能以很高的準确度檢測出手寫文本以及機器列印的文本。檢測出圖像中的詞之後,再将它們裁剪出來并将它們全部儲存下來。 預處理詞圖像 應該怎麼樣對圖像進行預處理?這完全取決于你接下來要做什麼。如果想要分類手寫的和機器列印的詞,需要所有圖像都處于灰階模式。為了将圖像轉換為灰階圖像,還需要使用 OpenCV:

imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)           

這是手寫詞嗎? 這是一個分類問題:确定一張特定圖像中的詞是「手寫詞」還是「機打詞」。作者浏覽了多篇文章和研究論文,發現支援向量機(SVM)是解決這一問題的最佳方案,然後使用了來自 sklearn 軟體包的 SVM 分類器來完成這一任務。對于用于分類的資料集,作者提到了一個很好的手寫詞圖像有标注資料集 IAM:http://www.fki.inf.unibe.ch/databases/iam-handwriting-database對于機器列印的詞圖像,作者收集了大約 2000 張詞圖像。下面是用于預測的特征: 

1. 平均像素強度

2. 像素強度的标準差

3. Otsu 門檻值

4. 像素強度直方圖中局部最大值的數量

5. 屬于像素強度上面的四分之一的像素的百分比

6. 屬于像素強度下面的四分之一的像素的百分比

 按照上面來看,所有特征都與圖像的像素強度有關聯。下一個問題是:如何找到像素強度?灰階圖像的像素值就是像素的強度,同樣也可以使用 OpenCV 和數學運算來完成這一任務。 使用 TensorFlow 的 HTR 這是本文所有問題中最具有挑戰性的問題。在嘗試了不同的解決方案之後(包括在手寫字元資料集上重新訓練 Tesseract),結果顯示 Harald Scheidl 這篇文章的方法最佳:https://towardsdatascience.com/build-a-handwritten-text-recognition-system-using-tensorflow-2326a3487cd5作者使用了類似的方法,不過做了一些小修改,在這裡使用了神經網絡,由 5 個卷積神經網絡(CNN)層、2 個循環神經網絡(RNN)層和 1 個連接配接主義時間分類(CTC)層構成。用于訓練這個神經網絡的資料集是 IAM 資料集,但你也可以使用任何有标注的詞圖像資料集。

一文解讀光學字元識别(OCR)與手寫文本識别(HTR)

圖 1.2:來自 Herald Scheidl 文章的示意圖 CNN 層的輸入是大小為 128×32 的灰階值圖像。CNN 層的輸出是一個序列,其包含 32 項,其中每一項都有 256 個特征。這些特征再進一步由 RNN 層處理,但是,某些特征已經表現出了與輸入圖像的特定高層面性質的高度相關性。

一文解讀光學字元識别(OCR)與手寫文本識别(HTR)

圖 1.3:來自 Herald Scheidl 的文章的示意圖 圖 1.3 展示了處理一張包含文本「little」的圖像時,可視化的 RNN 輸出矩陣。最上面的圖表中的矩陣包含了字元的分數,這些字元中的最後一項(第 80 個)是一個 CTC 空白标簽。其它矩陣項,從上到下分别對應于如下字元:!」#&』()*+,-./0123456789:;?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 可以看到,大多數時間裡,被預測的字元都剛好出現在它們在圖像中的位置處(比如,你可以比較看看圖像與圖表中 i 的位置。隻有最後一個字元 e 沒有對齊。但這其實沒有問題,因為 CTC 操作是無分割的,而且不在乎絕對位置。最下面的圖表展示了字元 l、i、t、e 和 CTC 空白标簽的分數,該文本可以輕松地被解碼:我們隻需要從每個時間步驟取出最可能的字元即可,這會構成所謂的最佳路徑,然後我們丢棄重複的字元,最後丢棄所有空白,得到:「l—-ii—t-t—l-…-e」→「l—-i—t-t—l-…-e」→「little」。 更多有關如何實作這一方法的細節資訊,請參看 Herald Scheidl 的文章。Tesseract(OCR) Tesseract 是目前最好的用于機器列印字元識别的開源 OCR 工具。Tesseract 支援 Unicode(UTF-8)字元集,可以識别超過 100 種語言,還包含多種輸出支援,比如純文字、PDF、TSV 等。但是為了得到更好的 OCR 結果,還必須提升提供給 Tesseract 的圖像的品質。注意,在執行實際的 OCR 之前,Tesseract 會在内部執行多種不同的圖像處理操作(使用 Leptonica 庫)。通常它表現不錯,但在某些情況下的效果卻不夠好,導緻準确度顯著下降。 在将圖像傳遞給 Tesseract 之前,可以嘗試以下圖像處理技術,但具體使用哪些技術取決于你想要讀取的圖像: 

1. 反轉圖像

2. 重新縮放

3. 二值化

4. 移除噪聲

5. 旋轉/調整傾斜角度

 所有這些操作都可以使用 OpenCV 或通過 Python 使用 numpy 實作。 簡單總結一下,本文介紹了與 OCR 和 HTR 相關的一些問題和可能的解決方案。如果你想要真正了解,一定要親自動手實作它們看看。