iOS实战篇:[译]iOS扩充--OCR光学字符识别(内附项目GitHub地址)

PHP是最好的 2018-04-18 11:54:44 ⋅ 879 阅读


原博客地址Tesseract OCR tutorial

之前在用扫描全能王的时候, 一直在思考这个功能是怎么实现的, 最近找到了一下资料, 和大家一起分享一下.

1.OCR是什么?

OCR(Optical Character Recognition) 光学字符识别, 是从图像中电子扫描提取文本的过程, 可以在文档编辑等多种形式重用它,例如: 文本搜索/压缩等用途。

OCR这是广泛用于你的平板电脑进行扫描文件、手写涂鸦等,  新闻报道(2015/01/14)谷歌将此添加到他们的应用程序之中, 今天我们共同学习在自己的iPhone上如何使用它!

OCR开源库地址---Tesseract;

2. 介绍Tesseract

Tesseract OCR 虽很牛逼,但有以下一些限制:

1. Unlike some OCR engines (like those used by the U.S. Postal Service to sort mail), 
Tesseract is unable to recognize handwriting and is limited to about 64 fonts in total.
Tesseract不可以识别出手写的字, 并且字数仅限于约64个 <有些疑惑>;
2. Tesseract需要一些预处理提高OCR结果;图像需要适当比例,尽可能多的形象对比,有水平排列的文本。
3. 最后, Tesseract OCR 只能工作在Linux, Windows, and Mac OS X平台之上;


(ーー゛) 那怎么才能在iOS设备上使用呢??

幸运的是: 有Objective-C对Tesseract OCR包装一层的框架可以利用在swift和iOS设备上, 
不要担心, swift兼容版本包括这个套装软件.

3. Love In A Snap

你怎么都不会想到Ray Wenderlich会在蓝色情人节(Valentine’s Day)前夕更新这篇文章, 对吧? 肯定不会! 我们设法找出万全方法打动你内心的欲望。与你共同创建爱的礼物! -_-

在这片教程里, 你将会学到怎么使用Google开源的框架---Tesseract, 你可以通过Love In A Snap来让你拍照的爱情诗和“让它自己的”取代原诗人的缪斯女神的名字与自己的感情的对象的名称。准备留下深刻印象吧!

3.1 开始

你可以从github 下载初始项目到本地;

这个压缩包包含几个文件:

1. LoveInASnap: Xcode项目;
2. Tesseract Resources: Tesseract框架和语言包;
3. Image Resources: 几张样张图片包含的文字之后可以使用.


打开当前工程 LoveinASnap.xcodeproj,你会发现在从Storyboard中关联到ViewController.swift中有一些@IBOutlets和空白的@IBAction方法;

在代码中你看到有两个方法来处理展示和关闭View的活动状态;

func addActivityIndicator() {
  activityIndicator = UIActivityIndicatorView(frame: view.bounds)
  activityIndicator.activityIndicatorViewStyle = .WhiteLarge
  activityIndicator.backgroundColor = UIColor(white: 0, alpha: 0.25)
  activityIndicator.startAnimating()
  view.addSubview(activityIndicator)
}
 
func removeActivityIndicator() {
  activityIndicator.removeFromSuperview()
  activityIndicator = nil
}

接下来有一些方法是移动View的位置防止键盘遮到输入框;

func moveViewUp() {  
if topMarginConstraint.constant != originalTopMargin {    
   return  }  topMarginConstraint.constant -= 135  UIView.animateWithDuration(0.3, animations: { () -> Void in    self.view.layoutIfNeeded()  }) } func moveViewDown() {  
   if topMarginConstraint.constant == originalTopMargin {    
       return  }  topMarginConstraint.constant = originalTopMargin  UIView.animateWithDuration(0.3, animations: { () -> Void in    self.view.layoutIfNeeded()  }) }

最后, 剩余的方法依据用户的交互来处理键盘和View的位置, moveViewUp()moveViewDown()

@IBAction func backgroundTapped(sender: AnyObject) {
  view.endEditing(true)
  moveViewDown()
} 
func textFieldDidBeginEditing(textField: UITextField) {
  moveViewUp()
} 
@IBAction func textFieldEndEditing(sender: AnyObject) {
  view.endEditing(true)
  moveViewDown()
} 
func textViewDidBeginEditing(textView: UITextView) {
  moveViewDown()
}

尽管重要的是用户体验(UX--User Experience),但这些方法是本教程最关键的部分,所以提前准备好了界面, 这样你就可以马上进入有趣的编码阶段。

在编写代码前, 先编译 运行一个项目, 点击一下界面, 感受一下UI, 目前TextView还不可以编辑, 点击输入框可以吊起和关闭键盘, 你可以为这个APP带来生命! Yes .You Can _


3.2 添加Tesseract Framework

3.2.1.第一步添加TesseractOCR.framework;

在解压的文件中找到Tesseract Resources文件夹, 在Xcode中添加TesseractOCR.framework, 确保添加时选中的是Copy items if needed, 最终点击Finish;

3.2.2.第二步添加tessdata

同样的方式添加tessdata文件夹;

3.2.3.添加系统依赖库, 包括

1. libstdc++.6.0.9.dylib(or libstdc++.6.0.9.tbd);
2. CoreImage.framework;
3. TesseractOCR.framework

3.2.4.配置

1.选中Build Settings利用上边的搜索框搜索Other Linker Flags, 在已经存在的keys中拼接上-lstdc++<亲测没改没问题>, 然后使用同样的方法在Build Settings下找到C++ Standard Library, 并将之设置为Compiler Default; 在找到Enable Bitcode将之设置为NO;

2.因为Tesseract是一个OC框架, 所以需要创建一个桥接头文件,

关于iOS OC与Swift混编的问题就不在此描述了;

LoveInASnap-Bridging-Header.h中添加

#import <TesseractOCR/TesseractOCR.h>


至此你就可以在项目中使用该框架了.

3.3 加载图片

第一步骤需要在OCR APP 中添加被扫描的图片, 最简单的方法是利用UIImagePickerController来从相册或相机中获取.

打开ViewController.swifttakePhoto()添加代码, 如下:

@IBAction func takePhoto(sender: AnyObject) {  
// 1. 关闭键盘, 使得view回到初始位置  view.endEditing(true)  moveViewDown()  // 2. 创建一个sheet样式的UIAlertController  let imagePickerActionSheet = UIAlertController(title: "Snap/Upload Photo",    message: nil, preferredStyle: .ActionSheet)  // 3. 打开相机, 如果在模拟器上,将不会出现该选项  if UIImagePickerController.isSourceTypeAvailable(.Camera) {    let cameraButton = UIAlertAction(title: "Take Photo",      style: .Default) { (alert) -> Void in        let imagePicker = UIImagePickerController()        imagePicker.delegate = self        imagePicker.sourceType = .Camera        self.presentViewController(imagePicker,          animated: true,          completion: nil)    }    imagePickerActionSheet.addAction(cameraButton)  }  // 4 取照片  let libraryButton = UIAlertAction(title: "Choose Existing",    style: .Default) { (alert) -> Void in      let imagePicker = UIImagePickerController()      imagePicker.delegate = self      imagePicker.sourceType = .PhotoLibrary      self.presentViewController(imagePicker,        animated: true,        completion: nil)  }  imagePickerActionSheet.addAction(libraryButton)  // 5 取消  let cancelButton = UIAlertAction(title: "Cancel",    style: .Cancel) { (alert) -> Void in  }  imagePickerActionSheet.addAction(cancelButton)  // 6 展示提示框  presentViewController(imagePickerActionSheet, animated: true,    completion: nil) }

如前所述列表中的限制条件,必须在一定位置约束才会出现最优OCR图像结果。如果图像太大或太小,Tesseract都可能返回不理想的结果,奇怪的是,崩溃的时候会报出EXC_BAD_ACCESS错误。

为此,需要写个方法来调整图像在尽可能不扭曲图像的前提下改变其宽高比。

3.4缩放图像保持长宽比

图像的宽高比例关系离不开width and height, 在数学中, 减少原始图像的大小不影响长宽比, 但是你必须保持宽高比不变。


当你知道一个图片的宽和高, 你所期望的最终宽高可以通过公式重新排列比例来计算:


由此产生两个公式:

1. Height1/Width1 * width2 = height2;
2. Width1/Height1 * height2 = width2 

你将使用这两个公式(formulas)来保证宽高比例;

ViewController.swift,添加如下方法

func scaleImage(image: UIImage, maxDimension: CGFloat) -> UIImage {
 
  var scaledSize = CGSize(width: maxDimension, height: maxDimension)
  var scaleFactor: CGFloat
 
  if image.size.width > image.size.height {
    scaleFactor = image.size.height / image.size.width
    scaledSize.width = maxDimension
    scaledSize.height = scaledSize.width * scaleFactor
  } else {
    scaleFactor = image.size.width / image.size.height
    scaledSize.height = maxDimension
    scaledSize.width = scaledSize.height * scaleFactor
  } 
  UIGraphicsBeginImageContext(scaledSize)
  image.drawInRect(CGRectMake(0, 0, scaledSize.width, scaledSize.height))
  let scaledImage = UIGraphicsGetImageFromCurrentImageContext()  UIGraphicsEndImageContext() 
  return scaledImage
}

传入maxDimension,该方法以图像的高度和宽度,哪个更大,设置最大的等于maxDimension。然后计算另一边图像基于比例适当,重绘计算原始图像以适应新框架,最后将新扩展的图像返回给调用的方法。

3.5 实现Tesseract OCR

ViewController.swift的下侧找到延展的类UIImagePickerControllerDelegate, 加入代码, 如下:

func imagePickerController(picker: UIImagePickerController,
  didFinishPickingMediaWithInfo info: [String : AnyObject]) {    
   let selectedPhoto = info[UIImagePickerControllerOriginalImage] as! UIImage    
   let scaledImage = scaleImage(selectedPhoto, maxDimension: 640)    addActivityIndicator()    dismissViewControllerAnimated(true, completion: {      self.performImageRecognition(scaledImage)    }) }

imagePickerController(_:didFinishPickingMediaWithInfo:)UIImagePickerDelegate的代理方法, 返回的是选择图片的信息(一个字典), 从info中利用key--UIImagePickerControllerOriginalImage获取到原始图片, 在利用刚写过的方法scaleImage(_:maxDimension:)来重新缩放图片;

当Tesseract工作时, 可以通过调用addActivityIndicator()来关闭用户交互, 显示活动状态; 然后可以关闭UIImagePicker, 通过performImageRecognition()进行加工;

添加如下方法, 这里将展示OCR的神奇之处:

func performImageRecognition(image: UIImage) {  
// 1 初始化G8Tesseract的对象tesseract  let tesseract = G8Tesseract()  
// 2 Tesseract将会从 .traineddata 文件搜索你指定的语言, 将会搜索fra.traineddata<法语>和eng.traineddata<英语>  tesseract.language = "eng+fra"  // 3 可以指定三种不同的engineMode类型, TesseractCubeCombined: 最快最不精确, .CubeOnly: 慢点但更加精确, 采用人工智能; .TesseractCubeCombined: 同时包含前两者, 最精确也最慢.  tesseract.engineMode = .TesseractCubeCombined  
// 4 因为字段不确定, 所以告诉引擎自动判断分段  tesseract.pageSegmentationMode = .Auto  
// 5 只有TesseractCubeCombined限制,最长扫描时间  tesseract.maximumRecognitionTime = 60.0  // 6 为了确保图片的对比度满足要求, Tesseract的过滤器<filter>g8_blackAndWhite()会增大对比度, 已达到更好的效果  tesseract.image = image.g8_blackAndWhite()  tesseract.recognize()  
   // 7 将获取到的文字展示到textView上  textView.text = tesseract.recognizedText  textView.editable = true  // 8 最后移除指示器表示扫描完成  removeActivityIndicator() }

被扫描的文字语言设置位置---第二条 [tesseract.language = "eng+fra"]


3.6 见证奇迹的时刻到了

找到之前主备的图片<包含英文和法文>, 打开模拟器, 直接将两张测试图片拖入模拟器, 将自动加入相册, 待稍后使用;

运行模拟器, Choose Existing--选择相册中的测试图片, 出现啦! 编译出来的文字在Textview上展示出来了, Tesseract确实完成了一个伟大的工作!!! NB



3.7 替换文字

其实吧, 主要获得到文字, 接下来的操作岂不任你摆布^_-, 原文中是一首爱情诗词, 一来在情人节之际表示一下爱慕之情, 二来再补充修改一下, 接下来就开始工作吧!

打开ViewController.swift, 找到已存在的swapText(), 修改代码如下:

@IBAction func swapText(sender: AnyObject) {  
// 1 保证替换和被替换代码不为空  if let text = textView.text,
   let findText = findTextField.text,    let replaceText = replaceTextField.text {    // 2 UITextView 的替换方法    textView.text =    textView.text.stringByReplacingOccurrencesOfString(findTextField.text,      withString: replaceTextField.text, options: [], range: nil)    // 3 将输入框置为空    findTextField.text = nil    replaceTextField.text = nil    // 4 结束任务, 取消键盘相应, View复位    view.endEditing(true)    moveViewDown()  } }

自己可以随便试试, 替换个你喜欢的ta的名字 _;

3.8 分享

可以获取, 可以更改, 怎么发给喜欢的人呢!!

最后这一段就交给分享了!

创建UIActivityViewController, 来进行操作分享,替换当前的方法sharePoem();

@IBAction func sharePoem(sender: AnyObject) {  
   // 1 判断时候为空  if textView.text.isEmpty {    
   return  }  
   // 2 初始化并赋值文字  let activityViewController = UIActivityViewController(activityItems:    [textView.text], applicationActivities: nil)  // 3  let excludeActivities = [    UIActivityTypeAssignToContact,    UIActivityTypeSaveToCameraRoll,    UIActivityTypeAddToReadingList,    UIActivityTypePostToFlickr,    UIActivityTypePostToVimeo]  activityViewController.excludedActivityTypes = excludeActivities  // 4 展示  presentViewController(activityViewController, animated: true,    completion: nil) }

注释第三步骤: UIActivityViewController有很多的类型, 进入苹果官方文档进行选择;

最终的项目地址

Complete! 去赢得一个你崇拜的Ta吧。

你可以把Lenore的名字换成你自己的,把这首诗通过邮件发给自己, 睡眼朦胧的痴呆的在情人节晚上, 举一杯清酒望着明月, 然后假装收到优雅成熟英国女王给你发来的邮件、浪漫、温馨、舒适....
突然电话响了, 就那么一句程序猿顿时从梦中惊醒....
你猜会是啥?


资源下载地址:

1.GitHub地址----Tesseract-OCR-iOS ---- Framework 
2. GitHub地址----更多语言包----tesseract-ocr, 请使用3.0.2或更高版本
3. 初始项目地址GitHub---OCR-Tutorial-start
4. 最终项目地址GitHub----OCR-Tutorial-end
由于某些小伙伴下载不了项目,个人就将之上传之GitHub,大家可以在OCR-Tutorial---start/end中【下载压缩包】。

如果觉得好,就东东小手点个赞O(∩_∩)O哈!

结束

Tesseract是很强大,但OCR的潜力是无限的。记住当你使用或提高OCR的功能时,作为传感,思维,如果你能破译字符使用你的眼睛或耳朵甚至指尖,那么字符识别中你是当之无愧的专家,已经完全有能力教学你的电脑去学习更多知识。

英文能力对不起看那么多美剧呀 !

原博客地址Tesseract OCR tutorial

更多精彩内容请关注“IT实战联盟”公众号哦~~~


全部评论: 0

    我有话说:

    iOS实战iOS 界面卡顿原因

    界面卡顿的原因在 VSync[1] 信号到来后,系统图形服务会通过 CADisplayLink 等机制通知 App,App 主线程开始在 CPU 中计算显示内容......

    抖音品质建设 - iOS启动优化《原理

    前言 启动是 App 给用户的第一印象,启动越慢用户流失的概率就越高,良好的启动速度是用户体验不可缺少的一环。启动优化涉及到的知识点非常多面也很广,一文章难以包含全部,所以拆分成两部分:原理和实践

    iOS TableView性能优化

    TableView的性能优化非常考验开发的基本功,之前做项目实战的时候经常被这个问题困扰

    SpringBoot+zk+dubbo架构实践(四):sb+zk+dubbo框架搭建(源码GitHub地址

    案例模拟了一个provider服务提供方和PC、Web两个服务消费方GitHub源码......

    iOS直播---音/视频采集/压缩(二)

    不好意思,我们来晚了! 但我们不会缺席。

    iOS直播---主要的概念(一)

    直播可谓风生水起, 热火朝天, 借此也对音视频进行一次深入学习, 希望有需要的大家一块学习.第一步对直播的大

    抖音品质建设 - iOS启动优化《实战

    实战,本文是实战。 原理:抖音品质建设-iO...

    VUE 开源库收藏版(一):史上最全面的学习资源 ,GitHub源码地址

    VUE 开源库收藏版(一):史上最全面的学习资源 ,GitHub源码地址

    『黑科技』开源 IP 地址定位库 ip2region,99.9%的准确率

    ip2region 是什么?ip2region 是准确率 99.9% 的 IP 地址定位库,0.0x毫秒级查

    iOS性能优化实践:头条抖音如何实现OOM崩溃率下降50%+

    iOS OOM 崩溃在生产环境中的归因一直是困扰业界已久的疑难问题,字节跳动旗下的头条、抖音等产品也面临同样的问题。在字节跳动性能与稳定性保障团队的研发实践中,我们自研了一款基于内存快照技术并且可

    架构实战(十二):Spring Boot 分布式Session共享Redis

    分布式Web网站一般都会碰到集群session共享问题,小编整理了一套解决方案,GitHub 源码地址哦~~~

    今日头条 iOS 安装包大小优化 - 新阶段、新实践

    前言 今日头条 iOS 端从 2016 年起就关注到了安装包大小的问题,并启动了包大小优化。2017 年,我们将当时的经验发表为技术文章 《干货|今日头条iOS端安装包大小优化—思路与实践

    WeCube 2.7.1 发布,一站式 IT 架构管理和运维管理工具

    WeCube简介 微众银行在分布式架构实践的过程中,发现将银行核心系统构建于分布式架构之上,会遇到一些与传统单体应用不同的痛点(例如,服务器增多,部署难度大;调用链长,全链路跟踪困难; 系统复杂

    Netbox 2.9.10 发布,IP 地址与数据中心管理工具

    NetBox 是一个 IP 地址管理(IP address management,IPAM)和数据中心基础设施管理(data center infrastructure management

    Netbox 2.11.1 发布,IP 地址与数据中心管理工具

    NetBox 是一个 IP 地址管理(IP address management,IPAM)和数据中心基础设施管理(data center infrastructure management

    Node实战:阶段项目(九)

    项目整体预览 项目github地址 界面逼格还行-_- 主要功能: 登陆; 退出; 所用的主要模块: express, 路由.静态文件.模块分工等; express-session, 采用

    前端实战-聊聊JavaScript

    内存生命周期、分配存、使用分配的内存(读与写操作),当应用程序不再需要时,释放掉已分配的

    GitHub竟然有基于SpringCloud的“网约车”项目源码

    有人问小编有没有开源的“网约车”项目源码,并且最好是采用微服务架构设计,这样可以投入技术团队进行二次开发。 小编在GitHub上还真找到了这个项目,接下来一起看一看吧! 项目介绍 该项目是一款标准且

    SpringBoot+zk+dubbo架构实践(五):搭建微服务电商架构(GitHub地址

    集成了mybatis和swagger让接口可视化并完成了一些增删改查的基础业务,对了还有个分页查询!