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

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

Robotic eye

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

安装html

准备java

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

配置Vagrantgithub

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

输入如下命令来下载Homestead Improved Vagrant配置到一个名为orc的文件夹:正则表达式

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

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

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

修改为:

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

一样要在hosts文件中添加

192.168.10.10       homestead.app

安装Tesseract

下一步是安装Tesseract

由于Homestead Improved 使用debian,咱们能够在使用vagrant ssh登录虚拟机后使用apt-get 来安装它,简单运行以下命令:

sudo apt-get install tesseract-ocr

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

测试并定制安装

咱们将使用PHP包装,可是以前咱们能够在命令行测试Tesseract。

首先保存这个图片sign.png

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

tesseract sign.png out

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

如今尝试sign2.jpg

tesseract sign2.jpg out

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

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

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

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

解压:

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

而后把文件复制到以下目录:

/usr/share/tesseract-ocr/tessdata

例如

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

如今咱们再次执行原来的命令可是要用 –l

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

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

能够经过重复上述过程来使用任意语言。

配置应用程序

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

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

记住这篇教程的全部代码都能在Github上得到。

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

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

而后创建三个文件夹:

- public - uploads - views

咱们须要上传表单(views\index.twig):

<html>   <head>     <title>OCR</title>   </head>   <body>      <form action="" method="post" enctype="multipart/form-data">       <input type="file" name="upload">       <input type="submit">     </form>    </body> </html>

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

<html>   <head>     <title>OCR</title>   </head>   <body>      <h2>Results</h2>      <textarea cols="50" rows="10">{{ text }}</textarea>      <hr>      <a href="/">← Go back</a>    </body> </html>

如今创建skeleton Silex app (public\index.php):

<php  require __DIR__.'/../vendor/autoload.php';  use Symfony\Component\HttpFoundation\Request;  $app = new Silex\Application();  $app->register(new Silex\Provider\TwigServiceProvider(), [   'twig.path' => __DIR__.'/../views', ]);  $app['debug'] = true;  $app->get('/', function() use ($app) {    return $app['twig']->render('index.twig');  });  $app->post('/', function(Request $request) use ($app) {      // TODO  });  $app->run();

若是你在浏览器访问这个应用,你应该能看到一个文件上传表单。若是你在使用Homestead Improved Vagrant,你能够经过以下连接访问该应用。

http://homestead.app/

下一步是实现文件上传。Silex使得这项工做很是简单;$request包含一个files组件,咱们能够经过它来得到任意上传的文件,代码:

// Grab the uploaded file $file = $request->files->get('upload');  // Extract some information about the uploaded file $info = new SplFileInfo($file->getClientOriginalName());  // Create a quasi-random filename $filename = sprintf('%d.%s', time(), $info->getExtension());  // Copy the file $file->move(__DIR__.'/../uploads', $filename);

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

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

在图像上实现OCR至关简单,咱们只需调用方法recognize()。

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

最后咱们把结果展现到结果页面:

return $app['twig']->render(     'results.twig',     [         'text'  =>  $text,     ] );

在一些图片上尝试,看看它效果怎样。若是你有困难,能够参考这个

一个实际的例子

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

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

结果应该以下:

:ii‘i Customer Service Helplines  British Airways Helpline  09040 490 541

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

为了提取相关信息,有以下几件事咱们能够作。

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

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

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

因此咱们采用两步处理。

  1. 尝试提取多是电话号码的数字串。

  2. 用一个库轮流评估每个候选字符,一旦找到一个有效电话号码则中止。

第一步,咱们能够用一个基本的正则表达式。能够用谷歌电话库来肯定一个数字串是不是合法电话号码。

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

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

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

别忘了升级:

composer update

如今咱们能够写一个函数,输入为一个字符串,尝试提取一个合法的电话号码

/** * Parse a string, trying to find a valid telephone number. As soon as it finds a * valid number, it'll return it in E1624 format. If it can't find any, it'll * simply return NULL. * * @param  string   $text           The string to parse * @param  string   $country_code   The two digit country code to use as a "hint" * @return string | NULL */ function findPhoneNumber($text, $country_code = 'GB') {    // Get an instance of Google's libphonenumber   $phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance();    // Use a simple regular expression to try and find candidate phone numbers   preg_match_all('/(\+\d+)?\s*(\(\d+\))?([\s-]?\d+)+/', $text, $matches);    // Iterate through the matches   foreach ($matches as $match) {      foreach ($match as $value) {        try {          // Attempt to parse the number         $number = $phoneUtil->parse(trim($value), $country_code);             // Just because we parsed it successfully, doesn't make it vald - so check it         if ($phoneUtil->isValidNumber($number)) {            // We've found a telephone number. Format using E.164, and exit           return $phoneUtil->format($number, \libphonenumber\PhoneNumberFormat::E164);          }        } catch (\libphonenumber\NumberParseException $e) {          // Ignore silently; getting here simply means we found something that isn't a phone number        }      }   }    return null;  }

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

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

如今咱们能够以下使用:

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

咱们须要给谷歌电话库提供一个提示来讲明这个号码是哪一个国家的。你也能够改为你本身的国家。

咱们把全部的这些打包在一个新的路由中:

$app->post('/identify-telephone-number', function(Request $request) use ($app) {    // Grab the uploaded file   $file = $request->files->get('upload');    // Extract some information about the uploaded file   $info = new SplFileInfo($file->getClientOriginalName());    // Create a quasi-random filename   $filename = sprintf('%d.%s', time(), $info->getExtension());    // Copy the file   $file->move(__DIR__.'/../uploads', $filename);    // Instantiate the Tessearct library   $tesseract = new TesseractOCR(__DIR__ . '/../uploads/' . $filename);    // Perform OCR on the uploaded image   $text = $tesseract->recognize();    $number = findPhoneNumber($text, 'GB');    return $app->json(     [       'number'     =>  $number,     ]   );  });

咱们如今有简单的API的基础—-也就是JSON响应-—咱们能够用来做为一个简单的移动应用的后端,这款应用能够用来从一幅图中添加联系人,打电话。

总结

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

相关文章
相关标签/搜索