PHP OCR实战:用Tesseract从图像中读取文字

Optical Character Recognition (OCR)即光学字符辨识是把打印文本转换成一个数字表示的过程。它有各种各样的实际应用–从数字化印刷书籍、创建收据的电子记录,到车牌识别甚至破解基于图像的验证码。

Tesseract是一个能实现OCR的开源项目。你能在*Nix系统,Mac系统和Windows系统上运行这个项目,但是只要使用一个库,我们就能在PHP项目中使用它了。本教程的目的是教你如何使用。

安装

准备

为了让事情变得简单和一致的, 我们将使用虚拟机(本文使用Vagrant)来运行应用程序,这会涉及到安装PHP和Nginx,我们将安装
Tesseract来分别演示过程。如果你想自己基于现有Debian-based系统安装Tesseract,你可以跳过下一部分—或者查看the README来获得在其他*nix上,Mac系统或者Windows的安装指导.

配置Vagrant

为了配置Vagrant以跟上本教程,完成如下步骤。或者你也可以简单的从Github获得代码。

输入以下命令来下载Homestead Improved Vagrant配置到一个名为orc的文件夹:

git clone https://github.com/Swader/homestead_improved ocr

将Nginx配置文件Homestead.yml中的以下代码:


  1. sites: 
  2.     - map: homestead.app 
  3.       to: /home/vagrant/Code/Project/public 

修改成:


  1. sites: 
  2.     - map: homestead.app 
  3.       to: /home/vagrant/Code/public 

同样要在hosts文件中添加


  1. 192.168.10.10       homestead.app 

安装Tesseract

下一步是安装Tesseract

因为Homestead Improved 使用debian,我们可以在使用vagrant ssh登陆虚拟机后使用apt-get 来安装它,简单运行如下命令:


  1. sudo apt-get install tesseract-ocr 

正如上文提到的,在the README中有其他的操作系统对应教程。

测试并定制安装

我们将使用PHP包装,但是之前我们可以在命令行测试Tesseract。

首先保存这个图片sign.png

在虚拟机中,执行如下命令来从图片中读取文字


  1. tesseract sign.png out 

这将在当前文件夹创建一个文件:out.txt里面应该有单词:CAUTION

现在尝试sign2.jpg


  1. tesseract sign2.jpg out 

这次产生单词Einbahnstral’ie。很接近但不正确—虽然图像中的文字相当清晰,它没能识别字符ß。

为了获使Tesseract正常读取字符串,我们需要安装一些新的语言文件—就本例来说,德语。

这里有一个全面的可用语言文件列表,但我们直接下载所需的文件:


  1. wget https://tesseract-ocr.googlecode.com/files/tesseract-ocr-3.02.deu.tar.gz 

解压:


  1. tar zxvf tesseract-ocr-3.02.deu.tar.gz 

然后把文件复制到如下目录:


  1. /usr/share/tesseract-ocr/tessdata 

例如


  1. cp deu-frak.traineddata /usr/share/tesseract-ocr/tessdata 
  2. cp deu.traineddata /usr/share/tesseract-ocr/tessdata 

现在我们再次执行原来的命令但是要用 –l


  1. tesseract sign2.jpg out -l deu 
  2.  
  3.     “deu” 是德语的 ISO 639-3码. 

这次,文字应该是Einbahnstraße(正确的)。

可以通过重复上述过程来使用任意语言。

配置应用程序

我们将使用这个库来用PHP使用Tesseract。

我们将建立一个极简的web应用:用户上传图片,并查看OCR处理结果。我们将使用Silex microframework 来实现。不要担心你不熟悉它,这个应用本身很简单。

记住这篇教程的所有代码都能在Github上获得。

第一步是用Composer来安装依赖文件:


  1. composer require silex/silex twig/twig thiagoalessio/tesseract_ocr:dev-master 

然后建立三个文件夹:


  1. - public 
  2. - uploads 
  3. - views 

我们需要上传表单(views\index.twig):


  1. <html> 
  2.   <head> 
  3.     <title>OCR</title> 
  4.   </head> 
  5.   <body> 
  6.  
  7.     <form action="" method="post" enctype="multipart/form-data"> 
  8.       <input type="file" name="upload"> 
  9.       <input type="submit"> 
  10.     </form> 
  11.  
  12.   </body> 
  13. </html> 

需要一个结果展示页面(views\results.twig)::


  1. <html> 
  2.   <head> 
  3.     <title>OCR</title> 
  4.   </head> 
  5.   <body> 
  6.  
  7.     <h2>Results</h2> 
  8.  
  9.     <textarea cols="50" rows="10">{{ text }}</textarea> 
  10.  
  11.     <hr> 
  12.  
  13.     <a href="/">← Go back</a> 
  14.  
  15.   </body> 
  16. </html> 

现在建立skeleton Silex app (public\index.php):


  1. <php 
  2.  
  3. require __DIR__.'/../vendor/autoload.php'; 
  4.  
  5. use Symfony\Component\HttpFoundation\Request; 
  6.  
  7. $app = new Silex\Application(); 
  8.  
  9. $app->register(new Silex\Provider\TwigServiceProvider(), [ 
  10.   'twig.path' => __DIR__.'/../views', 
  11. ]); 
  12.  
  13. $app['debug'] = true; 
  14.  
  15. $app->get('/', function() use ($app) { 
  16.  
  17.   return $app['twig']->render('index.twig'); 
  18.  
  19. }); 
  20.  
  21. $app->post('/', function(Request $request) use ($app) { 
  22.  
  23.     // TODO 
  24.  
  25. }); 
  26.  
  27. $app->run(); 

如果你在浏览器访问这个应用,你应该能看到一个文件上传表单。如果你在使用Homestead Improved Vagrant,你可以通过如下链接访问该应用。


  1. http://homestead.app/ 

下一步是实现文件上传。Silex使得这项工作非常简单;$request包含一个files组件,我们可以通过它来获得任意上传的文件,代码:


  1. // Grab the uploaded file 
  2. $file = $request->files->get('upload'); 
  3.  
  4. // Extract some information about the uploaded file 
  5. $info = new SplFileInfo($file->getClientOriginalName()); 
  6.  
  7. // Create a quasi-random filename 
  8. $filename = sprintf('%d.%s', time(), $info->getExtension()); 
  9.  
  10. // Copy the file 
  11. $file->move(__DIR__.'/../uploads', $filename); 

如你所见,我们产生随机文件名来减少文件名冲突—但在本应用中,我们怎么命名文件是不重要的。一旦我们在本地有一份文件拷贝,我们就可以产生一个Tessearct库的实例,然后进行分析:


  1. // Instantiate the Tessearct library 
  2. $tesseract = new TesseractOCR(__DIR__ . '/../uploads/' . $filename); 

在图像上实现OCR相当简单,我们只需调用方法recognize()。


  1. // Perform OCR on the uploaded image 
  2. $text = $tesseract->recognize(); 

最后我们把结果展示到结果页面:


  1. return $app['twig']->render( 
  2.     'results.twig', 
  3.     [ 
  4.         'text'  =>  $text, 
  5.     ] 
  6. ); 

在一些图片上尝试,看看它效果怎样。如果你有困难,可以参考这个

一个实际的例子

让我们来看OCR一个更实用的例子。在本例中,我们尝试在图像中找到一个格式化的电话号码。

看看下面一幅图,上传到你的应用:

结果应该如下:


  1. :ii‘i 
  2. Customer Service Helplines 
  3.  
  4. British Airways Helpline 
  5.  
  6. 09040 490 541 

它没有挑出正文文本,这是我们能料到的,因为图片质量太差。虽然识别了号码但是也有一些“噪声”。

为了提取相关信息,有如下几件事我们可以做。

你可以让Tesseract 把它的结果限制在一定的字符集内,所以我们告诉它只返回数字型的内容代码如下:


  1. $tesseract->setWhitelist(range(0,9)); 

但这样有个问题。它常常把非数字字符解释成数字而非忽略它们。比如“Bob”可能被解释称数字“808”。

所以我们采用两步处理。

  1. 尝试提取可能是电话号码的数字串。
  2. 用一个库轮流评估每一个候选字符,一旦找到一个有效电话号码则停止。

第一步,我们可以用一个基本的正则表达式。可以用谷歌电话库来确定一个数字串是否是合法电话号码。

备注:我已在Sitepoint 写过关于谷歌电话库的内容

让我们给谷歌电话库添加一个PHP 端口,修改composer.json,添加:


  1. "giggsey/libphonenumber-for-php": "~7.0" 

别忘了升级:


  1. composer update 

现在我们可以写一个函数,输入为一个字符串,尝试提取一个合法的电话号码


  1. /** 
  2. * Parse a string, trying to find a valid telephone number. As soon as it finds a 
  3. * valid number, it'll return it in E1624 format. If it can't find any, it'll 
  4. * simply return NULL. 
  5. * @param  string   $text           The string to parse 
  6. * @param  string   $country_code   The two digit country code to use as a "hint" 
  7. * @return string | NULL 
  8. */ 
  9. function findPhoneNumber($text, $country_code = 'GB') { 
  10.  
  11.   // Get an instance of Google's libphonenumber 
  12.   $phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance(); 
  13.  
  14.   // Use a simple regular expression to try and find candidate phone numbers 
  15.   preg_match_all('/(\+\d+)?\s*(\(\d+\))?([\s-]?\d+)+/', $text, $matches); 
  16.  
  17.   // Iterate through the matches 
  18.   foreach ($matches as $match) { 
  19.  
  20.     foreach ($match as $value) { 
  21.  
  22.       try { 
  23.  
  24.         // Attempt to parse the number 
  25.         $number = $phoneUtil->parse(trim($value), $country_code);    
  26.  
  27.         // Just because we parsed it successfully, doesn't make it vald - so check it 
  28.         if ($phoneUtil->isValidNumber($number)) { 
  29.  
  30.           // We've found a telephone number. Format using E.164, and exit 
  31.           return $phoneUtil->format($number, \libphonenumber\PhoneNumberFormat::E164); 
  32.  
  33.         } 
  34.  
  35.       } catch (\libphonenumber\NumberParseException $e) { 
  36.  
  37.         // Ignore silently; getting here simply means we found something that isn't a phone number 
  38.  
  39.       } 
  40.  
  41.     } 
  42.   } 
  43.  
  44.   return null; 
  45.  

希望注释能解释这个函数在干什么。注意如果这个库没能从字符串中解析出一个合法的电话号码它会抛出一个异常。这不是什么问题;我们直接忽略它并继续下一个候选字符。

如果我们找到一个电话号码,我们以E.164的形式返回它。这提供了一个国际化的号码,我们可以用来打电话或者发送SMS。

现在我们可以如下使用:


  1. $text = $tesseract->recognize(); 
  2. $number = findPhoneNumber($text, 'GB'); 

我们需要给谷歌电话库提供一个提示来说明这个号码是哪个国家的。你也可以改成你自己的国家。

我们把所有的这些打包在一个新的路由中:


  1. $app->post('/identify-telephone-number', function(Request $request) use ($app) { 
  2.  
  3.   // Grab the uploaded file 
  4.   $file = $request->files->get('upload'); 
  5.  
  6.   // Extract some information about the uploaded file 
  7.   $info = new SplFileInfo($file->getClientOriginalName()); 
  8.  
  9.   // Create a quasi-random filename 
  10.   $filename = sprintf('%d.%s', time(), $info->getExtension()); 
  11.  
  12.   // Copy the file 
  13.   $file->move(__DIR__.'/../uploads', $filename); 
  14.  
  15.   // Instantiate the Tessearct library 
  16.   $tesseract = new TesseractOCR(__DIR__ . '/../uploads/' . $filename); 
  17.  
  18.   // Perform OCR on the uploaded image 
  19.   $text = $tesseract->recognize(); 
  20.  
  21.   $number = findPhoneNumber($text, 'GB'); 
  22.  
  23.   return $app->json( 
  24.     [ 
  25.       'number'     =>  $number, 
  26.     ] 
  27.   ); 
  28.  
  29. }); 

我们现在有简单的API的基础—-也就是JSON响应-—我们可以用来作为一个简单的移动应用的后端,这款应用可以用来从一幅图中添加联系人,打电话。

总结

OCR有许多应用——并且很容易整合进你的应用(超过你的预期)。本文中,我们安装了开源OCR包;并使用一个包装器库,把它整合进一个非常简单的PHP应用。我们只是触及到了所有可能性的表面,希望这能给你一些想法,帮你想想怎么在你自己的应用中使用OCR。

作者:邱康

来源:51CTO

时间: 2024-10-31 23:57:44

PHP OCR实战:用Tesseract从图像中读取文字的相关文章

c c++图像中的文字识别

问题描述 c c++图像中的文字识别 类似于大漠插件的,dm.findstr 函数,还有,ocr控件怎么用?有源码吗? 解决方案 OCR 控件,都不会提供源代码,这可是核心支持.三款常见的OCR识别控件功能对比

如何用 php 从 .jpg 图像中读取 exif

read_exif_data (PHP 4 ) read_exif_data -- Reads header information stored in TIFF and JPEG images Description array exif_read_data ( string filename, string sections, bool arrays, bool thumbnail) Note: The read_exif_data() function is an alias for ex

《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——2.1节简析Android安装文件

2.1 简析Android安装文件 Android多媒体应用开发实战详解:图像.音频.视频.2D和3D 当下载并安装Android后,会在其安装目录中看到一些安装文件.了解这些文件具体是干什么用的,对于我们后面的驱动开发知识学习十分有用,所以在本节的内容中将简要介绍这些安装文件的基本知识. 2.1.1 Android SDK目录结构 安装Android SDK后,其安装目录的具体结构如图2-1所示. temp:里面包含了一些常用的文件模板. tools:包含了一些通用的工具文件. usb_dri

【OpenCV】访问图像中每个像素的值 (I)

最近要做的东西要对每个像素值进行处理,所以上网搜... 居然发现搜出来的好文章都是一个人写的,而且还是一个妹子..于是收藏之...按时间顺序发! 转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7557063 !!此篇是基于IplImage* (C接口或者说2.1之前版本的接口,新的Mat的访问方式请参考博文: <访问Mat图像中每个像素的值>) IplImage是OpenCV中CxCore部分基础的数据结构,用来表示图像,其中

实战分析从“沙盒”中挽救的站

沙盒期是指: 新站上线搜索引擎不能判断该站是垃圾站还是正规站,就把它放进沙盒中,我们优化中文站是针对百度搜索引擎来说的在这期间具体的表现就是关键词没有排名,网站出沙盒的时间大约在半个月到两个月之间. 我做的医疗类的生发类产品相关的网站,大家都知道,包括我之前都讲过,医疗类的网站不好优化和管理,我这个站,建站初期就进入的"沙盒",如果有朋友遇到和我一样的情况,请别着急,更不要放弃你的爱站,你辛辛苦苦的也至少培养了一段时间,不能就这么放弃,我们要把它从"沙盒"中捞出来,

如何在 SQL Server2000 中保存图像及读取图像信息

server //////////////////////////////////////////////////////////////////////////////////Author: stardicky ////E-mail: stardicky@hotmail.com ////QQNumber: 9531511 ////CompanyName: Ezone International ////Class: HBS-0308 ////title: 如何在 SQL Server2000

ps中怎么把图像中的路径复制到另一个图像中?

  photoshop中将图像中的路径复制到另一个图像中 要在路径选择工具下操作 1.点击文件 新建命令. 2.点击确定. 3.点击确定后 界面会切换到新建的图像文件. 4.鼠标左键点击原来的图像文件标签. 5.点击路径选择工具. 6.鼠标左键在路径内部按下并向上拖动至新建图像标签处停留一秒钟. 7.在按住鼠标停留一秒后会切换到新建图像文件 然后向新建图像文件内部拖动鼠标. 8.将鼠标拖动到新建文件中心位置处松开鼠标 路径复制完毕. 9.切换到原来的图像文件 路径还在. 分类: PS入门教程

图像处理-如何在单幅图像中消去阴影

问题描述 如何在单幅图像中消去阴影 在对图像处理时,由于图像中的阴影出现,导致算法无法进行,怎样可以将单幅图像里的阴影消去 解决方案 /*********************************************/ //阴影检测 /*********************************************/ CvPoint downleft,upright; int cnt; int dir[8][2]={-1,-1,-1,0,-1,1,0,1,0,-1,1,1,1

通过图像处理检测图像中的印刷品是否展平

问题描述 通过图像处理检测图像中的印刷品是否展平 针对一幅图像,利用图像处理算法检测图像中的印刷品是否展平,哪里出现变形?求指导