Статьи

OCR в PHP: чтение текста с изображений с помощью Tesseract

Оптическое распознавание символов (OCR) — это процесс преобразования печатного текста в цифровое представление. Он имеет множество практических применений — от оцифровки печатных книг, создания электронных записей квитанций до распознавания номерных знаков и даже обхода CAPTCHA на основе изображений.

Robotic eye

Tesseract — это программа с открытым исходным кодом для выполнения распознавания текста. Вы можете запустить его на системах * Nix, Mac OSX и Windows, но используя библиотеку, мы можем использовать ее в приложениях PHP. Этот учебник разработан, чтобы показать вам, как.

Установка

подготовка

Для простоты и согласованности мы будем использовать виртуальную машину для запуска приложения, которое мы предоставляем с помощью Vagrant. Это позаботится об установке PHP и Nginx, хотя мы установим Tesseract отдельно, чтобы продемонстрировать процесс.

Если вы хотите установить Tesseract на свою собственную, существующую систему на основе Debian, вы можете пропустить эту следующую часть или, в качестве альтернативы, посетить README для получения инструкций по установке на других * nix системах, Mac OSX (подсказка — используйте MacPorts !) Или Windows.

Vagrant Setup

Чтобы настроить Vagrant, чтобы вы могли следовать инструкциям, выполните следующие шаги. Кроме того, вы можете просто получить код из Github .

Введите следующую команду, чтобы загрузить конфигурацию Homestead Improved Vagrant в каталог с именем ocr :

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

Давайте изменим конфигурацию Nginx в Homestead.yml из:

 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 Binary

Следующим шагом является установка двоичного файла Тессеракта.

Поскольку Homestead Improved использует дистрибутив Linux на основе Debian, мы можем использовать apt-get для его установки после входа в виртуальную vagrant ssh с помощью vagrant ssh . Это так же просто, как выполнить следующую команду:

 sudo apt - get install tesseract - ocr 

Как я упоминал выше, в README есть инструкции для других операционных систем.

Тестирование и настройка установки

Мы собираемся использовать оболочку PHP, но прежде чем мы начнем строить, мы можем проверить, что Tesseract работает с использованием командной строки.

Сначала щелкните правой кнопкой мыши и сохраните это изображение .

( Изображение предоставлено Clipart Panda )

В виртуальной vagrant ssh ( vagrant ssh ) выполните следующую команду, чтобы «прочитать» образ и выполнить процесс распознавания:

 tesseract sign . png out 

Это создает файл в текущей папке с именем out.txt который все хорошо, должен содержать слово «ВНИМАНИЕ».

Теперь попробуйте с файлом sign2.jpg :

( Изображение является адаптированной версией этого ).

 tesseract sign2 . jpg out 

На этот раз вы должны обнаружить, что он произвел слово «Einbahnstral’ie». Это близко, но это не правильно — даже несмотря на то, что текст на изображении довольно четкий и ясный, он не смог распознать символ eszett (ß).

Чтобы 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».

Не стесняйтесь добавлять дополнительные языки, повторяя этот процесс.

Настройка приложения

Мы собираемся использовать эту библиотеку-оболочку для использования Tesseract из PHP.

Мы собираемся создать действительно простое веб-приложение, которое позволит людям загружать изображения и видеть результаты процесса распознавания. Для его реализации мы будем использовать микрорамку Silex — хотя не беспокойтесь, если вы с ней не знакомы, так как само приложение будет очень простым.

Помните, что весь код для этого урока доступен на 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 = "/" > &larr; Go back </a> 

   </body> 
 </html> 

Теперь создайте скелет приложения Silex ( 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, вы найдете его по следующему URL:

 http : //homestead.app/ 

Следующим шагом является загрузка файла. Silex делает это действительно легко; объект $request содержит компонент files , который мы можем использовать для доступа к любым загруженным файлам. Вот некоторый код для обработки загруженного файла (обратите внимание, что это идет по маршруту POST):

 // 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 (); 

Наконец, мы можем отобразить страницу результатов, передав ей результаты OCR:

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

Попробуйте это на некоторых изображениях, и посмотрите, как это работает. Если у вас возникли проблемы с распознаванием изображений, вам может быть полезно обратиться к руководству по улучшению качества .

Практический пример

Давайте посмотрим на более практическое применение технологии OCR. В этом примере мы попытаемся найти и отформатировать номер телефона, встроенный в изображение.

Посмотрите на следующее изображение и попробуйте загрузить его в свое приложение:

An image containing a telephone number

Результаты должны выглядеть так:

 : ii ' i Customer   Service   Helplines 





 British   Airways   Helpline 

 09040   490   541 

Он не подхватил основной текст, который мы могли ожидать из-за низкого качества изображения. Он идентифицировал номер телефона, но там также есть некоторый дополнительный «шум».

Чтобы попытаться извлечь соответствующую информацию, есть несколько вещей, которые мы можем сделать.

Вы можете указать Tesseract ограничить его вывод определенными диапазонами символов. Таким образом, мы можем сказать, чтобы он возвращал только цифры, используя следующую строку:

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

Однако есть проблема с этим. Вместо того, чтобы игнорировать нечисловые символы, он обычно интерпретирует буквы как цифры. Например, имя «Боб» можно интерпретировать как число «808».

Вместо этого давайте используем двухэтапный процесс:

  1. Попытка извлечь строки чисел, которые могут быть телефонными номерами
  2. Используйте библиотеку для проверки каждого кандидата по очереди, останавливаясь, когда мы находим действительный номер телефона

Для первой части мы можем использовать элементарное регулярное выражение. Чтобы попытаться определить, является ли строка чисел действительным номером телефона, мы можем использовать libphonenumber от Google .

Примечание : я написал о libphonenumber здесь на Sitepoint как часть статьи, озаглавленной Работа с телефонными номерами в JavaScript .

Давайте добавим порт PHP библиотеки libphonenumber в наш файл 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' ); 

Мы должны предоставить libphonenumber «подсказку» о том, в какой стране находится телефонный номер. Вы можете изменить это для своей страны.

Мы могли бы обернуть все это в новый маршрут:

 $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-приложение. Мы только коснулись поверхности того, что возможно, но, надеюсь, это дало вам некоторые идеи относительно того, как вы можете использовать эту технологию в своих собственных приложениях.