[译]适用于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对象。

从照片库中再次构建:

但极可能你的结果并不完美。还有改进的余地......

相关文章
相关标签/搜索