[譯]OpenCV OCR and text recognition with Tesseract

By Adrian Rosebrock on September 17, 2018 in Deep Learning, Optical Character Recognition (OCR), Tutorials python

點擊這裏下載這篇文章的源代碼linux

圖片描述
在本教程中,您將學習如何使用OpenCV OCR(光學字符識別)。咱們將執行文本檢測(1)和(2)文字識別使用OpenCV,Python和Tesseract。
幾周前,我向您展現瞭如何執行文本檢測使用OpenCV的EAST深度學習模型。使用這個模型咱們能夠檢測和定位的邊界框座標圖像中包含的文本。
下一步是把這些區域包含文本和實際識別和OCR文字使用OpenCV和Tesseract。git

Tesseract 進行 OpenCV OCR 和文本識別github

爲了執行 OpenCV OCR 和文本識別任務,咱們首先須要安裝 Tesseract v4,包括一個用於文本識別的高度準確的深度學習模型。
而後,我將展現如何寫一個 Python 腳本,使其可以:
(1)使用 OpenCV EAST 文本檢測器執行文本檢測,該模型是一個高度準確的深度學習文本檢測器,可用於檢測天然場景圖像中的文本。
(2)使用 OpenCV 檢測出圖像中的文本區域後,咱們提取出每一個文本 ROI 並將其輸入 Tesseract,從而構建完整的 OpenCV OCR 流程!算法

最後,我將展現一些使用 OpenCV 應用文本識別的示例,並討論該方法的缺陷。shell

下面就開始本教程的正式內容吧!segmentfault

如何安裝 Tesseract v4網絡

圖片描述
圖 1:Tesseract OCR 引擎於 20 世紀 80 年代出現,到 2018 年,它已經包括內置的深度學習模型,變成了更加穩健的 OCR 工具。Tesseract 和 OpenCV 的 EAST 檢測器是一個很棒的組合。
Tesseract 是一個很流行的 OCR 引擎,20 世紀 80 年代由 Hewlett Packard 開發,2005 年開源,自 2006 年起由谷歌贊助開發。該工具在受控條件下也能很好地運行,可是若是存在大量噪聲或者圖像輸入 Tesseract 前未經恰當處理,則性能較差。
深度學習對計算機視覺的各個方面都產生了影響,字符識別和手寫字體識別也不例外。基於深度學習的模型可以實現史無前例的文本識別準確率,遠超傳統的特徵提取和機器學習方法。Tesseract 歸入深度學習模型來進一步提高 OCR 準確率只是時間問題,事實上,這個時間已經到來。app

Tesseract (v4) 最新版本支持基於深度學習的 OCR,準確率顯著提升。底層的 OCR 引擎使用的是一種循環神經網絡(RNN)——LSTM 網絡。機器學習

安裝 OpenCV

要運行本教程的腳本,你須要先安裝 3.4.2 或更高版本的 OpenCV。安裝教程可參考 https://www.pyimagesearch.com...,該教程可確保你下載合適的 OpenCV 和 OpenCV-contrib 版本。

在 Ubuntu 上安裝 Tesseract 4

在 Ubuntu 上安裝 Tesseract 4 的具體命令因你使用的 Ubuntu 版本而異(Ubuntu 18.0四、Ubuntu 17.04 或更早版本)。你可以使用 lsb_release 命令檢查 Ubuntu 版本:

$ lsb_release -a
No LSB modules are available.
Distributor ID:    Ubuntu
Description:    Ubuntu 18.04.1 LTS
Release:    18.04
Codename:    bionic

如上所示,個人機器上運行的是 Ubuntu 18.04,不過你在繼續操做以前須要先檢查本身的 Ubuntu 版本。
對於 Ubuntu 18.04 版本的用戶,Tesseract 4 是主 apt-get 庫的一部分,這使得經過下列命令安裝 Tesseract 很是容易:

$ sudo add-apt-repository ppa:alex-p/tesseract-ocr
$ sudo apt-get update
$ sudo apt install tesseract-ocr

若是沒有錯誤,那麼你應該已經在本身的機器上成功安裝了 Tesseract 4。

在 macOS 上安裝 Tesseract 4( 略,調皮)

驗證你的 Tesseract 版本
圖片描述

圖 2:個人系統終端截圖。我輸入 tesseract -v 命令來檢查 Tesseract 版本

確保安裝了 Tesseract 之後,你應該執行如下命令驗證 Tesseract 版本:

$ tesseract -v
tesseract 4.0.0-beta.3
 leptonica-1.76.0
  libjpeg 9c : libpng 1.6.34 : libtiff 4.0.9 : zlib 1.2.11
 Found AVX512BW
 Found AVX512F
 Found AVX2
 Found AVX
 Found SSE

只要輸出中包含 tesseract 4,那麼你就成功在系統中安裝了 Tesseract 的最新版本。

安裝 Tesseract + Python 捆綁

安裝好 Tesseract 庫以後,咱們須要安裝 Tesseract + Python 捆綁,這樣咱們的 Python 腳本就能夠與 Tesseract 通訊,並對 OpenCV 處理過的圖像執行 OCR。
若是你使用的是 Python 虛擬環境(很是推薦,你能夠擁有獨立的 Python 環境),那麼使用 workon 命令訪問虛擬環境:

$ workon cv

如上所示,我訪問了一個叫作 cv 的 Python 虛擬環境(cv 是「計算機視覺」的縮寫),你也能夠用其餘名字命名虛擬環境。

接下來,咱們將使用 pip 來安裝 Pillow(PIL 的 Python 版本),而後安裝 pytesseract 和 imutils:

$ pip install pillow
$ pip install pytesseract
$ pip install imutils

如今打開 Python shell,確認你導入了 OpenCV 和 pytesseract:

$ python
Python 3.6.5 (default, Apr  1 2018, 05:46:30) 
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> import pytesseract
>>> import imutils
>>>

恭喜!若是沒有出現導入錯誤,那麼你的機器如今已經安裝好,可使用 OpenCV 執行 OCR 和文本識別任務了。

理解 OpenCV OCR 和 Tesseract 文本識別

圖片描述

圖 3:OpenCV OCR 流程圖

如今咱們已經在系統上成功安裝了 OpenCV 和 Tesseract,下面咱們來簡單回顧一下流程和相關命令。
首先,咱們使用 OpenCV 的 EAST 文本檢測器來檢測圖像中的文本。EAST 文本檢測器將提供文本 ROI 的邊界框座標。咱們將提取每一個文本 ROI,將其輸入到 Tesseract v4 的 LSTM 深度學習文本識別算法。LSTM 的輸出將提供實際 OCR 結果。最後,咱們將在輸出圖像上繪製 OpenCV OCR 結果。
過程當中使用到的 Tesseract 命令必須在 pytesseract 庫下調用。在調用 tessarct 庫時,咱們須要提供大量 flag。最重要的三個 flag 是 -l、--oem 和 --psm。
-l flag 控制輸入文本的語言,本教程示例中使用的是 eng(English),在這裏你能夠看到 Tesseract 支持的全部語言:https://github.com/tesseract-...
--oem(OCR 引擎模式)控制 Tesseract 使用的算法類型。執行如下命令便可看到可用的 OCR 引擎模式:

$ tesseract --help-oem
OCR Engine modes:
  0    Legacy engine only.
  1    Neural nets LSTM engine only.
  2    Legacy + LSTM engines.
  3    Default, based on what is available.

咱們將使用--oem 1,這代表咱們但願僅使用深度學習 LSTM 引擎。
最後一個重要的 flag --psm 控制 Tesseract 使用的自動頁面分割模式:

$ tesseract --help-psm
Page segmentation modes:
  0    Orientation and script detection (OSD) only.
  1    Automatic page segmentation with OSD.
  2    Automatic page segmentation, but no OSD, or OCR.
  3    Fully automatic page segmentation, but no OSD. (Default)
  4    Assume a single column of text of variable sizes.
  5    Assume a single uniform block of vertically aligned text.
  6    Assume a single uniform block of text.
  7    Treat the image as a single text line.
  8    Treat the image as a single word.
  9    Treat the image as a single word in a circle.
 10    Treat the image as a single character.
 11    Sparse text. Find as much text as possible in no particular order.
 12    Sparse text with OSD.
 13    Raw line. Treat the image as a single text line,
       bypassing hacks that are Tesseract-specific.

對文本 ROI 執行 OCR,我發現模式 6 和 7 性能較好,可是若是你對大量文本執行 OCR,那麼你能夠試試 3(默認模式)。
若是你獲得的 OCR 結果不正確,那麼我強烈推薦調整 --psm,它能夠對你的輸出 OCR 結果產生極大的影響。

項目結構

你能夠從本文「Downloads」部分下載 zip。而後解壓縮,進入目錄。下面的 tree 命令使得咱們能夠在終端閱覽目錄結構:

$ tree --dirsfirst
.
├── images
│   ├── example_01.jpg
│   ├── example_02.jpg
│   ├── example_03.jpg
│   ├── example_04.jpg
│   └── example_05.jpg
├── frozen_east_text_detection.pb
└── text_recognition.py
 
1 directory, 7 files

咱們的項目包含一個目錄和兩個重要文件:
images/:該目錄包含六個含有場景文本的測試圖像。咱們將使用這些圖像進行 OpenCV OCR 操做。
frozen_east_text_detection.pb:EAST 文本檢測器。該 CNN 已經通過預訓練,可用於文本檢測。它是由 OpenCV 提供的,你也能夠在「Downloads」部分下載它。
text_recognition.py:咱們的 OCR 腳本。咱們將逐行 review 該腳本。它使用 EAST 文本檢測器找到圖像中的文本區域,而後利用 Tesseract v4 執行文本識別。

實現咱們的 OpenCV OCR 算法

如今開始用 OpenCV 執行文本識別吧!
打開 text_recognition.py 文件,插入下列代碼:

# import the necessary packages
from imutils.object_detection import non_max_suppression
import numpy as np
import pytesseract
import argparse
import cv2

本教程中的 OCR 腳本須要五個導入,其中一個已經內置入 OpenCV。
最顯著的一點是,咱們將使用 pytesseract 和 OpenCV。個人 imutils 包將用於非極大值抑制,由於 OpenCV 的 NMSBoxes 函數沒法適配 Python API。我注意到 NumPy 是 OpenCV 的依賴項。
argparse 包被包含在 Python 中,用於處理命令行參數,這裏無需安裝。
如今已經處理好導入了,接下來就來實現 decode_predictions 函數:

def decode_predictions(scores, geometry):
    # grab the number of rows and columns from the scores volume, then
    # initialize our set of bounding box rectangles and corresponding
    # confidence scores
    (numRows, numCols) = scores.shape[2:4]
    rects = []
    confidences = []
 
    # loop over the number of rows
    for y in range(0, numRows):
        # extract the scores (probabilities), followed by the
        # geometrical data used to derive potential bounding box
        # coordinates that surround text
        scoresData = scores[0, 0, y]
        xData0 = geometry[0, 0, y]
        xData1 = geometry[0, 1, y]
        xData2 = geometry[0, 2, y]
        xData3 = geometry[0, 3, y]
        anglesData = geometry[0, 4, y]
 
        # loop over the number of columns
        for x in range(0, numCols):
            # if our score does not have sufficient probability,
            # ignore it
            if scoresData[x] < args["min_confidence"]:
                continue
 
            # compute the offset factor as our resulting feature
            # maps will be 4x smaller than the input image
            (offsetX, offsetY) = (x * 4.0, y * 4.0)
 
            # extract the rotation angle for the prediction and
            # then compute the sin and cosine
            angle = anglesData[x]
            cos = np.cos(angle)
            sin = np.sin(angle)
 
            # use the geometry volume to derive the width and height
            # of the bounding box
            h = xData0[x] + xData2[x]
            w = xData1[x] + xData3[x]
 
            # compute both the starting and ending (x, y)-coordinates
            # for the text prediction bounding box
            endX = int(offsetX + (cos * xData1[x]) + (sin * xData2[x]))
            endY = int(offsetY - (sin * xData1[x]) + (cos * xData2[x]))
            startX = int(endX - w)
            startY = int(endY - h)
 
            # add the bounding box coordinates and probability score
            # to our respective lists
            rects.append((startX, startY, endX, endY))
            confidences.append(scoresData[x])
 
    # return a tuple of the bounding boxes and associated confidences
    return (rects, confidences)

decode_predictions 函數,在這篇文章中有詳細介紹(https://www.pyimagesearch.com...)。該函數:

使用基於深度學習的文本檢測器來檢測(不是識別)圖像中的文本區域。
該文本檢測器生成兩個陣列,一個包括給定區域包含文本的機率,另外一個陣列將該機率映射到輸入圖像中的邊界框位置。

EAST 文本檢測器生成兩個變量:
scores:文本區域的機率。
geometry:文本區域的邊界框位置。

兩個變量都是 decode_predictions 函數的參數。
該函數處理輸入數據,得出一個包含文本邊界框位置和該區域包含文本的相應機率的元組:
rects:該值基於 geometry,其格式更加緊湊,方便咱們稍後將其應用於 NMS。
confidences:該列表中的置信度值對應 rects 中的每一個矩形。
這兩個值都由 decode_predictions 函數得出。

注意:完美狀況下,旋轉的邊界框也在 rects 內,可是提取旋轉邊界框不利於解釋本教程的概念。所以,我計算了水平的邊界框矩形(把 angle 考慮在內)。若是你想提取文本的旋轉邊界框輸入 Tesseract,你能夠在第 41 行獲取 angle。

關於上述代碼塊的更多細節,參見 https://www.pyimagesearch.com...
[譯]
下面咱們來解析命令行參數:

# 構造參數分析器和分析參數
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", type=str,
    help="path to input image")
ap.add_argument("-east", "--east", type=str,
    help="path to input EAST text detector")
ap.add_argument("-c", "--min-confidence", type=float, default=0.5,
    help="minimum probability required to inspect a region")
ap.add_argument("-w", "--width", type=int, default=320,
    help="nearest multiple of 32 for resized width")
ap.add_argument("-e", "--height", type=int, default=320,
    help="nearest multiple of 32 for resized height")
ap.add_argument("-p", "--padding", type=float, default=0.0,
    help="amount of padding to add to each border of ROI")
args = vars(ap.parse_args())

咱們的腳本須要兩個命令行參數:
--image:輸入圖像的路徑。
--east:預訓練 EAST 文本檢測器的路徑。

下列命令行參數是可選的:
--min-confidence:檢測到的文本區域的最小几率。
--width:圖像輸入 EAST 文本檢測器以前須要從新調整的寬度,咱們的檢測器要求寬度是 32 的倍數。
--height:與寬度相似。檢測器要求調整後的高度是 32 的倍數。
--padding:添加到每一個 ROI 邊框的(可選)填充數量。若是你發現 OCR 結果不正確,那麼你能夠嘗試 0.0五、0.10 等值。

下面,咱們將加載和預處理圖像,並初始化關鍵變量:

圖片描述

第 82 行和 83 行,將圖像加載到內存中,並複製(這樣稍後咱們能夠在上面繪製輸出結果)。

獲取原始寬度和高度(第 84 行),而後從 args 詞典中提取新的寬度和高度(第 88 行)。咱們使用原始和新的維度計算比率,用於稍後在腳本中擴展邊界框座標(第 89 和 90 行)。

而後調整圖像大小,此處忽略長寬比(第 93 行)。

接下來,咱們將使用 EAST 文本檢測器:

圖片描述

第 99 到 101 行,將兩個輸出層名稱轉換成列表格式。而後,將預訓練 EAST 神經網絡加載到內存中(第 105 行)。

必須強調一點:你至少須要 OpenCV 3.4.2 版本,它有 cv2.dnn.readNet 實現。

接下來就是見證第一個「奇蹟」的時刻:

圖片描述

爲肯定文本位置,咱們:
在第 109 和 110 行構建 blob。詳情參見 https://www.pyimagesearch.com...
將 blob 輸入 EAST 神經網絡中,獲取 scores 和 geometry(第 111 和 112 行)。
使用以前定義的 decode_predictions 函數解碼預測(第 116 行)。
經過 imutils 方法進行非極大值抑制(第 117 行)。NMS 高效使用機率最高的文本區域,刪除其餘重疊區域。

如今咱們知道文本區域的位置了,接下來須要識別文本。咱們開始在邊界框上循環,並處理結果,爲實際的文本識別作準備:

圖片描述

咱們初始化 results 列表,使其包含咱們的 OCR 邊界框和文本(第 120 行)。而後在 boxes 上進行循環(第 123 行),咱們:
基於以前計算的比率擴展邊界框(第 126-129 行)。
填充邊界框(第 134-141 行)。
最後,提取被填充的 roi(第 144 行)。

本文的 OpenCV OCR 流程可使用一點 Tesseract v4「魔術」來完成:

圖片描述

第 151 行,咱們設置 Tesseract config 參數(英語、LSTM 神經網絡和單行文本)。
注:若是你獲取了錯誤的 OCR 結果,那麼你可能須要使用本教程開頭的指令配置 --psm 值。
第 152 行,pytesseract 庫進行剩下的操做,調用 pytesseract.image_to_string,將 roi 和 config string 輸入其中。
只用兩行代碼,你就使用 Tesseract v4 識別了圖像中的一個文本 ROI。記住,不少過程在底層發生。
咱們的結果(邊界框值和實際的 text 字符串)附加在 results 列表(第 156 行)中。
接下來,咱們繼續該流程,在循環的基礎上處理其餘 ROI。

如今,咱們來打印出結果,查看它是否真正有效:

圖片描述

第 159 行基於邊界框的 y 座標按自上而下的順序對結果進行了排序。
對結果進行循環,咱們:
將 OCR 處理過的文本打印到終端(第 164-166 行)。
從文本中去掉非 ASCII 字符,由於 OpenCV 在 cv2.putText 函數中不支持非 ASCII 字符(第 171 行)。
基於 ROI 繪製 ROI 周圍的邊界框和結果文本(第 173-176 行)。
展現輸出,等待即將按下的鍵(第 17九、180 行)。

OpenCV 文本識別結果

如今咱們已經實現了 OpenCV OCR 流程。
確保使用本教程「Downloads」部分下載源代碼、OpenCV EAST 文本檢測器模型和示例圖像。
打開命令行,導航至下載和提取壓縮包的位置,而後執行如下命令:

$ python text_recognition.py --east frozen_east_text_detection.pb \
    --image images/example_01.jpg
[INFO] loading EAST text detector...
OCR TEXT
========
OH OK

clipboard.png
圖 4:對 OpenCV OCR 的第一次嘗試成功!

咱們從一個簡單示例開始。

注意咱們的 OpenCV OCR 系統如何正確檢測圖像中的文本,而後識別文本。

下一個示例更具表明性,是一個現實世界圖像:

$ python text_recognition.py --east frozen_east_text_detection.pb \
    --image images/example_02.jpg
[INFO] loading EAST text detector...
OCR TEXT
========
® MIDDLEBOROUGH

clipboard.png

圖 5:更復雜的圖像示例,咱們使用 OpenCV 和 Tesseract 4 對這個白色背景的標誌牌進行了 OCR 處理。

再次,注意咱們的 OpenCV OCR 系統如何正肯定位文本位置和識別文本。可是,在終端輸出中,咱們看到了一個註冊商標 Unicode 符號,這裏 Tesseract 可能被欺騙,由於 OpenCV EAST 文本檢測器報告的邊界框與標誌牌後面的植物發生重疊。

下面咱們來看另外一個 OpenCV OCR 和文本識別示例:

$ python text_recognition.py --east frozen_east_text_detection.pb \
    --image images/example_03.jpg
[INFO] loading EAST text detector...
OCR TEXT
========
ESTATE

OCR TEXT
========
AGENTS

OCR TEXT
========
SAXONS

圖片描述

圖 6:使用 OpenCV、Python 和 Tesseract 對包含三個單詞的大標誌牌進行 OCR 處理。

該示例中有三個單獨的文本區域。OpenCV 的文本檢測器可以定位每個文本區域,而後咱們使用 OCR 準確識別每一個文本區域。

下一個示例展現了在特定環境下添加填充的重要性:

$ python text_recognition.py --east frozen_east_text_detection.pb \
    --image images/example_04.jpg 
[INFO] loading EAST text detector...
OCR TEXT
========
CAPTITO

OCR TEXT
========
SHOP

OCR TEXT
========
|.

圖片描述

圖 7:在這個烘培店場景圖像中,咱們的 OpenCV OCR 流程在處理 OpenCV EAST 文本檢測器肯定的文本區域時遇到了問題。記住,沒有一個 OCR 系統完美適用於全部狀況。那麼咱們可否經過更改參數來作得更好呢?

首先嚐試對這家烘培店的店面進行 OCR,咱們看到「SHOP」被正確識別,可是:
「CAPUTO」中的「U」被錯誤識別爲「TI」。
「CAPUTO'S」中的「'S」被漏掉。
「BAKE」被錯誤識別爲「|.」。

如今咱們添加填充,從而擴展 ROI 的邊界框座標,準確識別文本:

$ python text_recognition.py --east frozen_east_text_detection.pb \
    --image images/example_04.jpg --padding 0.05
[INFO] loading EAST text detector...
OCR TEXT
========
CAPUTO'S

OCR TEXT
========
SHOP

OCR TEXT
========
BAKE

圖片描述

圖 8:經過向 EAST 文本檢測器肯定的文本區域添加額外的填充,咱們可以使用 OpenCV 和 Tesseract 對烘培店招牌中的三個單詞進行恰當的 OCR 處理。

僅僅在邊界框的四角周圍添加 5% 的填充,咱們就可以準確識別出「BAKE」、「U」和「'S」。
固然,也有 OpenCV 的失敗案例:

$ python text_recognition.py --east frozen_east_text_detection.pb \
    --image images/example_05.jpg --padding 0.25
[INFO] loading EAST text detector...
OCR TEXT
========
Designer

OCR TEXT
========
a

圖片描述

圖 9:添加了 25% 的填充後,咱們的 OpenCV OCR 系統可以識別招牌中的「Designer」,可是它沒法識別較小的單詞,由於它們的顏色與背景色太接近了。咱們甚至沒法檢測到單詞「SUIT」,「FACTORY」可以檢測到,但沒法使用 Tesseract 識別。咱們的 OCR 系統離完美還很遠。

下面介紹了該 OCR 系統的一些侷限和不足,以及對改進 OpenCV 文本識別流程的建議。

侷限和不足

記住,沒有完美的 OCR 系統,尤爲是在現實世界條件下。指望 100% 的 OCR 準確率也是不切實際的。
咱們的 OpenCV OCR 系統能夠很好地處理一些圖像,但在處理另一些圖像時會失敗。該文本識別流程失敗存在兩個主要緣由:
文本被扭曲或旋轉。
文本字體與 Tesseract 模型訓練的字體相差太遠。

即便 Tesseract v4 與 v3 相比更增強大、準確,但該深度學習模型仍然受限於訓練數據。若是你的文本字體與訓練數據字體相差太遠,那麼 Tesseract 極可能沒法對該文本進行 OCR 處理。
其次,Tesseract 仍然假設輸入圖像/ROI 已經通過恰當清潔。而當咱們在天然場景圖像上執行文本識別時,該假設不老是準確。

總結

本教程介紹瞭如何使用 OpenCV OCR 系統執行文本檢測和文本識別。
爲了實現該任務,咱們
利用 OpenCV EAST 文本檢測器定位圖像中的文本區域。
提取每一個文本 ROI,而後使用 OpenCV 和 Tesseract v4 進行文本識別。
咱們還查看了執行文本檢測和文本識別的 Python 代碼。
該 OpenCV OCR 流程在一些狀況下效果很好,另外一些狀況下並不那麼準確。要想得到最好的 OpenCV 文本識別結果,我建議你確保:
輸入 ROI 儘可能通過清理和預處理。在理想世界中,你的文本應該可以與圖像的其餘部分完美分割,可是在現實狀況下,分割並不老是那麼完美。
文本是在攝像機 90 度角的狀況下拍攝的,相似於自上而下、鳥瞰的角度。若是不是,那麼角度變換能夠幫助你得到更好的結果。

以上就是此次的教程,但願對你們有所幫助!

相關文章
相關標籤/搜索