Используйте Swift и Apple's Vision, чтобы читать и интерпретировать текст вокруг вас

Вы также можете найти эту историю и многое другое в Think In Swift.



В iOS 11 Apple интегрировала библиотеку под названием Vision. Эта библиотека использует алгоритмы для выполнения ряда задач с изображениями и видео (обнаружение текста, штрих-коды и т. Д.).

Теперь, с iOS 13, Apple опубликовала новую библиотеку VisionKit, которая позволяет вам использовать сканер документов самой системы (тот же, который использует приложение Notes).

Давайте посмотрим, как вы можете разработать собственное распознавание текста в iOS 13 с помощью VisionKit.

Начало проекта

Чтобы проверить, как мы можем сканировать документ и распознавать его содержимое, мы создаем проект в Xcode 11 (помните, что VisionKit работает только на iOS 13+). Полную версию этого проекта можно найти на GitHub.

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

Для этого в файле Info.plist мы добавляем ключ Privacy — Camera Usage Description вместе с текстом, который будет отображаться для пользователя, когда он запрашивает разрешение.

Например: To be able to scan documents you must allow the use of the camera.

Если в разрешении отказано, когда мы хотим сканировать, появится следующее сообщение:

Дизайн интерфейса

Этот проект будет в основном состоять из UIImageView компонента, в котором мы покажем отсканированный документ с распознанным текстом, компонента UITextView, чтобы показать текст, распознанный сканером, и компонента UIButton для активации сканирования документа.

В этом проекте я буду делать все это с помощью кода, без использования раскадровок или .xib файлов.

Программирование интерфейса

Сначала мы создаем компонент ScanButton:

Затем компонент ScanImageView:

И, наконец, компонент OcrTextView:

Теперь мы вызываем их из ViewController и размещаем на экране:

Презентация контроллера сканирования - VNDocumentCameraViewController

Чтобы представить контроллер, который позволит нам сканировать документ, мы должны создать и представить экземпляр класса VNDocumentCameraViewController.

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

После configure() метода мы создаем scanDocument() метод:

Как видите, @objc был добавлен перед функцией, потому что, хотя мы программируем на Swift, #selector является методом Objective-C.

Кроме того, класс VNDocumentCameraViewController представляет протокол VNDocumentCameraViewControllerDelegate (который мы вызвали в scanVC.delegate = self), поэтому мы можем реализовать его методы.

Мы делаем это в расширении класса ViewController, чтобы наш код был более организованным:

Первый метод, documentCameraViewController (_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan), вызывается, когда мы отсканировали одну или несколько страниц и сохранили их (сначала Продолжить сканирование, а затем Сохранить).

Объект scan (VNDocumentCameraScan) содержит три параметра:

  • pageCount— количество (Int) отсканированных страниц.
  • imageOfPage(at index: Int)— Изображение (UIImage) страницы в указанном индексе.
  • title— заголовок (String) отсканированного документа. Убедившись, что один или несколько документов были отсканированы, перед удалением контроллера мы передаем отсканированное изображение компоненту scanImageView.

Второй метод, documentCameraViewController (_ controller: VNDocumentCameraViewController, didFailWithError error: Error), вызывается при возникновении ошибки при сканировании документа, поэтому именно на этом этапе мы должны выполнить некоторые действия по управлению ошибками.

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

Третий метод, documentCameraViewControllerDidCancel (_ controller: VNDocumentCameraViewController), вызывается при нажатии кнопки Cancel контроллера VNDocumentCameraViewController. Здесь мы только сбросим контроллер.

Распознавание текста

Теперь для распознавания и извлечения текста из отсканированных документов мы будем использовать фреймворк Apple Vision, уже интегрированный в iOS 11. В частности, мы будем использовать класс VNRecognizeTextRequest.

Этот класс, как указано в документации, ищет и распознает текст на изображении.

Для этого процесса нам понадобится запрос (экземпляр класса VNRecognizeTextRequest), в котором мы можем определить параметры распознавания текста:

  • customWords— Определенный нами набор слов для дополнения слов в словаре, который будет использоваться на этапе распознавания (например, имена, отметки и т. Д.).
  • minimumTextHeight— минимальная высота текста (по отношению к изображению), от которой будет происходить распознавание текста. Как Apple указывает в своей документации:

«Увеличение размера снижает потребление памяти и ускоряет распознавание за счет игнорирования текста, высота которого меньше минимальной. Значение по умолчанию - 1/32 или 0,03125 ».

В этом проекте мы применим, в качестве примера, некоторые из этих параметров:

На этом этапе мы создаем функцию configureOCR(), которая будет содержать функции для анализа, распознавания и извлечения текста из изображения:

Мы вызовем эту функцию в viewDidLoad() после метода configure().

В этой функции мы создаем экземпляр VNRecognizeTextRequest, который содержит только один аргумент, completionHandler, который вызывается каждый раз, когда на изображении обнаруживается текст.

На этом этапе происходит следующий процесс:

  • Сначала мы проверяем, что request.results содержит список наблюдений (типа VNRecognizedTextObservation), которые соответствуют строкам и предложениям, обнаруженным библиотекой Vision.
  • Затем мы перебираем этот список наблюдений. Каждое из этих наблюдений состоит из ряда возможных кандидатов на то, каким может быть распознанный текст, каждый из которых имеет определенный уровень достоверности. Выбираем первого кандидата и добавляем его в текстовую строку.
  • Наконец, мы показываем в элементе OcrTextView, что мы создали принцип полученного текста (не забудьте сделать это в основном потоке, поэтому мы используем Dispatch.main.async).

Обработка изображений

Наконец, нам нужно только обработать изображение, захваченное сканером.

Для них мы создаем функцию, которая примет параметр типа UIImage (захваченное изображение) и создаст экземпляр типа VNImageRequestHandler, в который мы передадим экземпляр ocrRequest, который мы создали в начале:

Как указано в документации, для создания экземпляра этого типа нам нужно использовать CGImage, а не UIImage (поскольку он работает с Core Graphics), поэтому мы получаем этот параметр из переданного изображения.

Мы также можем передать список параметров типа VNImageOption (который описывает конкретные свойства изображения или то, как с ним следует обращаться), хотя в этом случае мы не будем передавать их.

Наконец, мы применяем запрос распознавания текста (ocrRequest).

Этот метод processImage (_ image: UIImage) будет вызываться в конце метода documentCameraViewController (_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) и непосредственно перед закрытием контроллера с помощью controller.dismiss(animated: true).

Сканер Тест

Теперь мы можем протестировать приложение. Для этого включаем и делаем снимок.

Как видите, он отлично распознает текст изображения.

Заключение

Как мы видели, благодаря библиотекам Vision и VisionKit мы можем легко создать собственный сканер документов на нашем мобильном телефоне. Помните, что вы можете скачать весь проект на GitHub.