[譯]適用於iOS的Tesseract OCR教程

導語:在本教程中,您將學習如何使用Tesseract使用OCR讀取和處理從圖像中提取的文本。ios

本教程適用:Xcode 10.2,Swift 5, iOS 12.1 和TesseractOCRiOS (5.0.1)git

OCR是從圖像中電子提取文本的過程。您之前確定看到過它 - 它被普遍用於處理掃描文檔還有平板電腦上的手寫塗鴉,再到GoogleTranslate應用程序中的Word Lens技術github

在本教程中,您將學習如何使用由Google維護的開源OCR引擎Tesseract從愛情詩中獲取文本並使其成爲您本身的文本。準備好留下深入印象!swift

開 始

這裏下載本教程的材料,而後將文件夾解壓縮到方便的位置。xcode

Love In A Snap目錄包含: · Love In A Snap Starter: 本教程的初始工程 · Love In A Snap Final:最終完成的工程 · Resources:你須要使用OCR處理的圖片和包含Tesseract語言數據的目錄bash

在Xcode中打開Love In A Snap Starter/Love In A 網絡

Snap.xcodeproj,而後構建運行開始的app。熟悉一下UI。

回到Xcode,看一下ViewController.swift 它已經包含了幾個@IBOutlet和空的@IBAction方法,這幾個方法已經和Main.storyboard接口鏈接好了。它還包含了performImageRecognition(_:),在這個函數裏Tesseract進行處理。session

往下滾動你會看見:閉包

// 1
// MARK: - UINavigationControllerDelegate
extension ViewController: UINavigationControllerDelegate {
}
// 2
// MARK: - UIImagePickerControllerDelegate
extension ViewController: UIImagePickerControllerDelegate {
  // 3
  func imagePickerController(_ picker: UIImagePickerController,
    didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    // TODO: Add more code here...
  }
}

複製代碼
  1. 幫助你方便地添加圖片的UIImagePickerViewController須要UINavigationControllerDelegate來訪問圖片選擇控制器的代理方法。
  2. image picker也要UIImagePickerControllerDelegate來訪問圖片選擇控制器的代理方法;
  3. imagePickerController(_:didFinishPickingMediaWithInfo:)代理方法返回選擇的圖片;

如今,輪到你接管並將這個應用程序變爲現實!app

Tesseract的限制

Tesseract OCR很是強大,但確實有如下限制: · 與某些OCR引擎不一樣 - 例如美國郵政局用於對郵件進行分類的引擎 - Tesseract沒有接受過識別手寫的培訓,而且總共限制了大約100種字體。 · Tesseract須要一些預處理來改善OCR結果:圖像須要適當縮放,具備儘量多的圖像對比度,而且文本必須水平對齊。 · 最後,Tesseract OCR僅適用於Linux,Windows和Mac OS X.

哦不!你打算如何在iOS中使用它? Nexor Technology爲Tesseract OCR建立了兼容的Swift包裝器。

添加Tesseract框架

首先,您必須經過CocoaPods安裝Tesseract OCR iOS,這是一個普遍使用的iOS項目依賴管理器。

若是您還沒有在計算機上安裝CocoaPods,請打開終端,而後執行如下命令:

sudo gem install cocoapods
複製代碼

在請求完成CocoaPods安裝時輸入您的計算機密碼。

下一步,進入到Love In A Snap Starter項目的目錄下。若是你把它放到了桌面,就能夠用下面的命令

cd ~/Desktop/"Love In A Snap/Love In A Snap Starter"
複製代碼

而後輸入:

pod init
複製代碼

這將爲您的項目建立一個Podfile。用如下內容替換Podfile的內容:

platform :ios, '12.1'

target 'Love In A Snap' do
  use_frameworks!

  pod 'TesseractOCRiOS'

end
複製代碼

這告訴CocoaPods您但願將TesseractOCRiOS包含爲項目的依賴項。

回到終端,輸入:

pod install
複製代碼

這會將pod安裝到您的項目中。

當終端輸出指示時,「Please close any current Xcode sessions and use Love In A Snap.xcworkspace for this project from now on.」使用Xcode打開Love In A Snap.xcworkspace

Tessertact OCR如何工做

通常來講,OCR使用人工智能來查找和識別圖像中的文本。

一些OCR引擎依賴於一種稱爲機器學習的人工智能。機器學習容許系統經過識別和預測模式來學習和適應數據。

Tesseract OCR iOS引擎使用稱爲神經網絡的特定類型的機器學習模型。

神經網絡在人腦中的模型以後被鬆散地建模。咱們的大腦包含大約860億個鏈接的神經元,這些神經元被分組成各類網絡,可以經過重複學習特定的功能。相似地,在更簡單的尺度上,人工神經網絡接收多種樣本輸入,並經過隨時間的成功和失敗來學習,從而產生愈來愈準確的輸出。這些樣本輸入稱爲「訓練數據」。

在調教系統時,這個培訓數據:

  1. 經過神經網絡的輸入節點進入。
  2. 經過稱爲「邊緣」的節點間鏈接進行傳播,每一個鏈接都以輸入應該沿着該路徑傳播的感知機率加權。
  3. 經過一層或多層「隱藏」(即內部)節點,這些節點使用預約的啓發式處理數據。
  4. 經過輸出節點返回預測結果。

而後將該輸出與指望的輸出進行比較,並相應地調整邊緣權重,使得傳遞到神經網絡的後續訓練數據返回愈來愈準確的結果。

神經網絡的模式

Tesseract尋找像素,字母,單詞和句子的圖案。 Tesseract使用稱爲自適應識別的兩步方法。對數據進行一次傳遞以識別字符,而後第二次傳遞以填寫任何不太可能符合給定單詞或句子上下文的字母的字母。

添加訓練數據

爲了在給定語言的範圍內更好地磨練其預測,Tesseract須要特定於語言的訓練數據來執行其OCR。

導航到Finder中的Snap / Resources中的Love。 tessdata文件夾包含一堆英語和法語培訓文件。你將在本教程中處理的愛情詩主要是英文,但也包含一些法語。 Très浪漫主義!

如今,您將tessdata添加到您的項目中。 Tesseract OCR iOS要求您添加tessdata做爲referenced folder

  1. 將tessdata文件夾從Finder拖到Xcode左側Project導航器中的Love In A Snap文件夾中。
  2. 選擇Copy items if needed
  3. Added Folders選項設置爲Create folder references
  4. 確認選擇target而後點擊完成

添加tessdata做爲引用文件夾

您如今應該在導航器中看到一個藍色的tessdata文件夾。藍色表示引用了文件夾而不是Xcode組。

如今您已經添加了Tesseract框架和語言數據,如今是時候開始使用有趣的編碼了!

加載文件

首先,您須要先完成從設備的相機或照片庫訪問圖像的方法。

打開ViewController.swift 而後在takePhoto(_:)中加入下面的代碼:

// 1
let imagePickerActionSheet =
  UIAlertController(title: "Snap/Upload Image",
                    message: nil,
                    preferredStyle: .actionSheet)

// 2
if UIImagePickerController.isSourceTypeAvailable(.camera) {
  let cameraButton = UIAlertAction(
    title: "Take Photo",
    style: .default) { (alert) -> Void in
      // TODO: Add more code here...
  }
  imagePickerActionSheet.addAction(cameraButton)
}

// 3
let libraryButton = UIAlertAction(
  title: "Choose Existing",
  style: .default) { (alert) -> Void in
    // TODO: Add more code here...
}
imagePickerActionSheet.addAction(libraryButton)

// 4
let cancelButton = UIAlertAction(title: "Cancel", style: .cancel)
imagePickerActionSheet.addAction(cancelButton)

// 5
present(imagePickerActionSheet, animated: true)

複製代碼

import UIKit下面添加

import MobileCoreServices
複製代碼

這使ViewController能夠訪問kUTTypeImage抽象圖像標識符,您將使用它來限制圖像選擇器的媒體類型。

如今在cameraButton UIAlertAction的閉包中,用如下代碼替換// TODO註釋:

// 1
self.activityIndicator.startAnimating()
// 2
let imagePicker = UIImagePickerController()
// 3
imagePicker.delegate = self
// 4
imagePicker.sourceType = .camera
// 5
imagePicker.mediaTypes = [kUTTypeImage as String]
// 6
self.present(imagePicker, animated: true, completion: {
  // 7
  self.activityIndicator.stopAnimating()
})
複製代碼

一樣,在libraryButton的閉包裏面也添加:

self.activityIndicator.startAnimating()
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.mediaTypes = [kUTTypeImage as String]
self.present(imagePicker, animated: true, completion: {
  self.activityIndicator.stopAnimating()
})

複製代碼

這與您剛剛添加到cameraButton的閉包中的代碼相同,除了imagePicker.sourceType = .photoLibrary。在這裏,您將圖像選擇器設置爲顯示設備的照片庫而不是相機。

接下來,要處理捕獲或選定的圖像,請將如下內容插入imagePickerController(_:didFinishPickingMediaWithInfo :)

// 1
guard let selectedPhoto =
  info[.originalImage] as? UIImage else {
    dismiss(animated: true)
    return
}
// 2
activityIndicator.startAnimating()
// 3
dismiss(animated: true) {
  self.performImageRecognition(selectedPhoto)
}

複製代碼

您將在本教程的下一部分中編寫performImageRecognition代碼,可是,如今,只需打開Info.plist。將光標懸停在頂部單元格信息屬性列表上,而後在出現時單擊+按鈕兩次。

在這兩個新條目的密鑰字段中,分別添加Privacy – Camera Usage DescriptionPrivacy – Photo Library Usage Description。爲每一個選擇String類型。而後在「值」列中,分別在請求訪問其相機和照片庫的權限時,輸入要向用戶顯示的任何文本。

構建並運行您的項目。點擊Snap / Upload Image按鈕,您將看到剛剛建立的UIAlertController。

測試出操做表選項,並在出現提示時授予應用程序訪問相機和/或庫的權限。按預期確認照片庫和相機顯示。

注意:若是您在模擬器上運行,則沒有可用的物理相機,所以您將看不到「拍照」選項。

實現Tesseract OCR

首先,導入MobileCoreServices以使ViewController可使用Tesseract框架:

import TesseractOCR
複製代碼

如今,在performImageRecognition(_ :)中,用如下內容替換// TODO註釋:

// 1
if let tesseract = G8Tesseract(language: "eng+fra") {
  // 2
  tesseract.engineMode = .tesseractCubeCombined
  // 3
  tesseract.pageSegmentationMode = .auto
  // 4
  tesseract.image = image
  // 5
  tesseract.recognize()
  // 6
  textView.text = tesseract.recognizedText
}
// 7
activityIndicator.stopAnimating()
複製代碼

因爲這是本教程的內容,這裏有咱們一行一行的詳細解釋:

  1. 使用新的G8Tesseract對象初始化tesseract,該對象將使用英語(「eng」) - 和法語(「fra」) - 訓練有素的語言數據。請注意,詩的法語重音字符不在英文字符集中,所以必須包含法語訓練數據以便出現這些重音符號
  2. Tesseract提供三種不一樣的OCR引擎模式:.tesseractOnly,這是最快但最不許確的方法; .cubeOnly,因爲它採用了更多的人工智能,所以速度更慢但更準確;和.tesseractCubeCombined,它同時運行.tesseractOnly和.cubeOnly。 .tesseractCubeCombined是最慢的,但因爲它是最準確的,你將在本教程中使用它
  3. 默認狀況下,Tesseract假定它正在處理統一的文本塊,但您的樣本圖像有多個段落。 Tesseract的pageSegmentationMode讓Tesseract引擎知道文本的劃分方式。在這種狀況下,將pageSegmentationMode設置爲.auto以容許全自動頁面分段,從而可以識別段落中斷
  4. 將所選圖像分配給tesseract實例
  5. 告訴Tesseract開始識別你的文字
  6. 將Tesseract的識別文本輸出放入textView
  7. 自OCR完成後隱藏活動指示器

如今,是時候測試第一批新代碼了!

處理你的第一張圖片

在Finder中,導航到Love In A Snap / Resources / Lenore.png以查找示例圖像。

Lenore.png是一首寫給「Lenore」的愛情詩的形象,但經過一些編輯,你能夠把它變成一首確定會引發你所渴望的人的注意的詩!

雖然您能夠打印圖像的副本,而後使用應用程序拍攝照片以執行OCR,您能夠輕鬆本身並將圖像直接添加到設備的相機膠捲。這消除了人爲錯誤,進一步照明不一致,文本偏斜和打印有缺陷的可能性。畢竟,圖像已是黑暗和模糊的。

注意:若是您使用的是模擬器,只需將圖像文件拖放到模擬器上便可將其添加到其照片庫中。

構建並運行您的應用程序。點擊Snap / Upload Image,點擊Choose Existing,而後從照片庫中選擇樣本圖像以經過OCR運行它。

注意:您能夠放心地忽略TesseractOCR庫生成的數百個編譯警告。

哦哦!什麼都沒出現!這是由於當前的圖像尺寸太大,以致於Tesseract沒法處理。是時候改變了!

在保持縱橫比的同時縮放圖像

圖像的縱橫比是其寬度和高度之間的比例關係。從數學上講,要在不影響縱橫比的狀況下縮小原始圖像的大小,必須保持寬高比不變。

當您知道原始圖像的高度和寬度,而且您知道最終圖像的所需高度或寬度時,您能夠從新排列寬高比等式,以下所示:

由此咱們能夠獲得兩個公式: 公式1:當圖像的寬度大於其高度時。

Height1/Width1 * width2 = height2
複製代碼

公式2:當圖像的高度大於其寬度時。

Width1/Height1 * height2 = width2
複製代碼

如今,將如下擴展和方法添加到ViewController.swift的底部:

// MARK: - UIImage extension

//1
extension UIImage {
  // 2
  func scaledImage(_ maxDimension: CGFloat) -> UIImage? {
    // 3
    var scaledSize = CGSize(width: maxDimension, height: maxDimension)
    // 4
    if size.width > size.height {
      scaledSize.height = size.height / size.width * scaledSize.width
    } else {
      scaledSize.width = size.width / size.height * scaledSize.height
    }
    // 5
    UIGraphicsBeginImageContext(scaledSize)
    draw(in: CGRect(origin: .zero, size: scaledSize))
    let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    // 6
    return scaledImage
  }
}

複製代碼

如今,在performImageRecognition(_ :)的頂部加入:

let scaledImage = image.scaledImage(1000) ?? image
複製代碼

這將嘗試縮放圖像,使其不超過1,000點寬或長。若是scaledImage()沒法返回縮放圖像,則常量將默認爲原始圖像。

而後用下面的代碼代替tesseract.image = image

tesseract.image = scaledImage
複製代碼

這會將縮放後的圖像指定給Tesseract對象。

從照片庫中再次構建:

但極可能你的結果並不完美。還有改進的餘地......

相關文章
相關標籤/搜索