這次和大家聊聊文字識別相關的話題。 大家在平時肯定對各種掃描類的 APP 不陌生。 拿著手機攝像頭對著任何文字,直接將攝像頭中的文字內容轉換成手機上可編輯的字串。
文字識別,縮寫叫做 OCR,全稱 Optical character recognition,譯為光學字元識別。 關於他的完整定義可以在 Wikipedia 上面找到: en.wikipedia.org/wiki/Optica…。
完整的 OCR 演算法,並不簡單。 涉及到影象識別演算法,以及將從圖片中識別出來的文字轉換成我們程式中可以使用的二進位制形式。這其中還包括不同語言的字元如何識別,怎樣更精準的識別等等。
設想一下,如果作為開發者,讓你自己從頭開發這樣一套演算法,恐怕要花掉很大力氣。 不過好訊息是,我們生活在這個開源時代,早已經有很多前輩們為我們趟好了道路。 這也是我們今天要聊的主題, Tesseract 就是這樣一個開源庫,給定任意一張圖片,它可以識別出裡面所有的文字內容,並且 API 介面使用非常簡單。
Tesseract
Tesseract 是 Google 釋出的一款 OCR 開源庫,它支援多個變成語言環境,以及執行環境,其中包括我們這裡將要介紹的 iOS 環境。 今天就用它帶領大家開發一個屬於你自己的 OCR 應用。
首先,需要安裝 Tesseract, 最簡單的方式是用過 Cocoapods, 進入你的專案根目錄,輸入:
pod init
複製程式碼
然後,編輯生成的 Podfile 配置檔案:
target 'ocrSamples' do
use_frameworks!
pod 'TesseractOCRiOS'
end
複製程式碼
將 TesseractOCRiOS
加入配置列表中, 最後輸入:
pod install
複製程式碼
就完成了 TesseractOCRiOS
的安裝。如果你之前沒有接觸過 Cocoapods 可以參看我們之前的文章 swiftcafe.io/2015/02/10/…。
配置工作
安裝完成後, 我們還需要進行一下簡單的配置, 首先要在 Build Phases -> Link Binary With Libraries 中配置, 專案需要的依賴庫, CoreImage, libstdc++, 以及 TesseractOCRiOS 自身:
配置好依賴庫之後, 我們還需要將文字識別訓練資料新增進來, 訓練資料是什麼呢, TesseractOCRiOS
識別圖片的時候,會依照這個訓練資料的規則來識別文字。比如中文,英文等,都有對應的訓練資料,這可以理解為深度學習預先為我們訓練好的模型。用它來進行核心的識別演算法。
訓練資料是需要按照不同語言來區分的,Tesseract 有專門的頁面列出了所有可用的訓練資料:github.com/tesseract-o…。
比如我們這裡需要識別簡體中文,就可以下載 chi-sim 這個訓練資料:
然後將訓練資料拖放到工程中:
上圖中的 chi_sim.traineddata 是我們下載的訓練資料, 這裡面有一點要注意的是, 這個檔案必須要在 testdata 這個資料夾中。 並且這個資料夾要以 "Create Folder Reference" 的方式拖放進來:
這種引用方式和另外一種 "Create Groups" 的方式有什麼區別呢? 主要區別在於, 使用引用方式拖放進來的目錄, 在最後生成 APP 包的時候, Main Bunlde 中是以 testdata/chi_sim.traineddata 這樣的路徑形式儲存我們訓練資料資源的, 如果使用 "Create Groups" 方式,最終儲存的時候是會忽略資料夾名的,最後儲存在 Main Bundle 中的檔案是以 /chi_sim.traineddata 這個路徑存放的。
而 TesseractOCRiOS, 預設情況下是會在 testdata/chi_sim.traineddata 這個路徑查詢訓練資料的, 所以如果使用 "Create Groups" 方式拖入,會造成執行時找不到訓練資料,而報錯。 這點細節需要格外注意。
最後,為了讓 TesseractOCRiOS 能夠正確執行, 我們還需要關掉 BitCode, 否則會報編譯錯誤,我們需要在兩處都要關掉它,一個是至工程,另外一個是 Pods 模組, 如下圖:
開始編碼
做完上述的準備工作後, 我們就可以開始編碼了, 這裡只給大家展示最精簡的程式碼。 首先我們需要在主介面上顯示兩個控制元件,一個是我們預先儲存好的帶有文字的照片, 另外一個是用於展示識別結果的文字框:
override func viewDidLoad() {
super.viewDidLoad()
self.imageView = UIImageView(frame: CGRect(x: 0, y: 80, width: self.view.frame.size.width, height: self.view.frame.size.width * 0.7))
self.imageView?.image = UIImage(named: "textimg")
self.view.addSubview(self.imageView!)
self.textView = UITextView(frame: CGRect(x: 0, y: labelResult.frame.origin.y + labelResult.frame.size.height + 20, width: self.view.frame.size.width, height: 200))
self.view.addSubview(self.textView!)
}
複製程式碼
這裡面我們只將兩個控制元件的初始化關鍵程式碼寫出來,其他不重要的程式碼都略去。 然後就可以呼叫 TesseractOCRiOS 來進行文字識別了:
func recognizeText(image: UIImage) {
if let tesseract = G8Tesseract(language: "chi_sim") {
tesseract.engineMode = .tesseractOnly
tesseract.pageSegmentationMode = .auto
tesseract.image = image
tesseract.recognize()
self.textView?.text = tesseract.recognizedText
}
}
複製程式碼
所有識別相關的程式碼就都在這裡了。首先呼叫 G8Tesseract 進行初始化, 我們傳入訓練資料的名稱,這裡是 "chi_sim" 代表簡體中文。 engineMode
有三種可以選擇的模式, tesseractOnly,tesseractCubeCombined 和 cubeOnly。 我們使用第一種模式,採用訓練資料的方式。 cubeOnly 的意識就是使用更精準的 cube 方式, tesseractCubeCombined 就是兩種模式的結合使用。
cube 模式需要額外的模型資料, 大致樣例是這樣:
上圖是英文的 cube 識別模型。 簡體中文的模型我暫時沒有找到,所以我們這個例項中只是用到了 tesseractOnly 模式。 並且在沒有 cube 模型資料的情況下,我們是不用使用 tesseractCubeCombined 和 cubeOnly 的,否則會因為模型資料不存在而報錯。 大家如果能夠找到中文的 cube 模型,也歡迎在留言中反饋,這樣會讓這個文字識別更加精準。
其他的呼叫就不需要多講了, 將要識別的 image 物件設定給 Tesseract。 然後呼叫它的 recognize 方法進行識別, 最後將識別結果 tesseract.recognizedText 設定給 TextView。
最終的執行效果如下:
上面的圖片是我拍的 SwiftCafe 網站上一篇文章的照片, 從識別結果上看,還算比較準確。
總結
大家從上面的程式碼中應該也感受到了, Tesseract 雖然提供了本質上算是比較複雜的文字識別演算法, 但它提供給開發者的介面可以說得上是非常簡單。 OCR 文字識別從整體上來說,也可以算得上是 AI 的一個應用分支,在這個 AI 大行其道的時代,即便掌握一些應用技術,對我們開發者來說也可以很大的拓寬我們的視野。 發揮你的創意,也許類似 Tesseract 這些元件能夠幫助你創造 AI 時代的新銳應用。
當然, Tesseract 目前自身還有一些缺陷,比如它只能識別印刷字型,而不能精準的識別手寫字型。 不過那又怎麼樣呢,本來相當複雜的 OCR 演算法,可以讓我們用非常少的代價應用起來,還是一件對開發者非常幸福的事情。
照例,本文中的示例工程程式碼已經放到 Github 中,大家有需要可以直接下載:github.com/swiftcafex/…。
**如果你覺得這篇文章有幫助,還可以關注微信公眾號 swift-cafe,會有更多我的原創內容分享給你~ **