Как мы распознаем фото документов пользователей. Часть I

Привет, Хабр! Я Илья, Data Scientist в inDriver. В работе нам часто приходится распознавать документы водителей или пассажиров для их верификации в приложении. Наша команда выработала свой подход к идентификации текста и фото, которым я хотел бы поделиться.

В первой части статьи кратко расскажу о том, как мы распознаем фото документов и текст на них. Во второй более предметно поговорю о моделях CRAFT, CRNN и их использовании. Приятного чтения!

image-loader.svgСодержание

Минутка истории

Задача оптического распознавания символов (OCR — optical character recognition) — старая проблема, восходящая к 1970-м годам, когда была разработана первая технология OCR c омни-шрифтами (omni-font). Сложность этой задачи обусловлена естественными особенностями текстов:

  • В некоторых алфавитах найти и распознать буквы очень сложно (например, в арабском, китайском, особенно в курсиве).

  • Существует много разных шрифтов и стилей, некоторые символы слишком похожи на другие (например, буквы I и l, цифра 0 и буква O).

  • Рукописный текст бывает всех форм и размеров.

Все методы распознавания текста с глубоким обучением можно условно разделить на 3 большие категории:

  • Character-based. Эти методы сначала пытаются найти и распознать определенные местоположения отдельных символов, а затем сгруппировать в слова.

  • Word-based. Методы решают распознавание текста как проблему классификации слов, где классы — общие слова на определенном языке.

  • Sequence-to-sequence. Методы рассматривают OCR как проблему маркировки последовательностей. Одни из самых ранних работ по этому типу методов была написана китайскими авторами. Статья является оригинальной работой по описанию модели CRNN. Также в ней дается подробный обзор конкретной архитектуры GRU-CNN с вычислительной точки зрения. Различные модификации моделей CRNN работают лучше, чем другие, на многих эталонных наборах данных OCR.

3 категории распознавания текста3 категории распознавания текста

Первой программой, распознающей кириллицу, был «AutoR» российской компании «ОКРУС». Программа начала распространяться в 1992 году и работала под управлением операционной системы DOS. Алгоритм «AutoR» был разработан и испытан еще в конце 1960-х годов биофизиками и выпускниками МФТИ Г.М. Зенкиным и А.П. Петровым (1, 2).

Распознавание фото документов

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

  • Часто необходимо распознать не весь документ, а какую-то область или поле.

  • Фотографии имеют низкое разрешение из-за старой модели телефона, или документ расположен далеко от камеры.

  • Фотографии сделаны под углом по оси Z. 

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

  • Используются разные шрифты и разные типы документов в пределах страны или города.

  • Фотография может быть перевернута на 90, 180 или 270 градусов.

Распознавание документов в inDriver включает в себя 2 основных этапа:

  1. Segmentation. Сегментация области документа, которая должна быть распознана.

  2. Recognition. Распознавание текста или Detection (детекция) и распознавание.

Расскажу подробнее о сегментации. Задачи компьютерного зрения разделяют на несколько видов:

  • Classification. Классификация изображения по типу объекта, которое оно содержит.

  • Object Detection. Обнаружение всех объектов указанных классов и определение охватывающей рамки для каждого из них (bounding box).

  • Semantic Segmentation. Выделение разных классов объектов на изображении, включая среду. 

  • Instance Segmentation. Разделение объектов одного класса на разные объекты.

  • Panoptic Segmentation. Объединение задач семантической и инстанс-сегментации. Также в задаче паноптической сегментации каждому пикселю изображения должна быть присвоена ровно одна метка.

Примеры сегментации изображенийПримеры сегментации изображений

В первой итерации мы использовали instance segmentation модель на TensorFlow2 архитектуры MASK RCNN (TensorFlow Hub). С помощью Fine-Tuning дообучили модель на наших данных. Она позволила получать bounding box и mask размеченной области документов. 

Но вскоре мы отказались от ее использования. Проблема — много зависимостей от TensorFlow Object Detection API. Нужно было сериализовывать данные в собственный формат TFRecords

Было решено перейти на PyTorch-фреймворк detectron2. На тестах метрики у моделей из detectron2 были выше, чем у модели на TensorFlow2(даже без тестов можно сравнить метрики на TFHub и model zoo detectron2). Для detecron2 использовали предобученные веса модели СOCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x (в зависимости от ресурсов и времени можно выбрать готовые веса).

Датасет создавался с помощью ручной разметки через приложение labelme, а потом конвертировался в формат COCO датасета, где был написан свой, немного адаптированный скрипт. Была попытка использовать Label Studio, но софт показался не совсем дружелюбным и больше ориентированным на команду разметки.

Так как в документах обычно одно уникальное поле и оно не дублируется, можно было использовать модели из semantic segmentation (маски) или object detection (bounding box). Но мы применили instance segmentation, чтобы получить маски и боксы.

Следующий шаг после определения нужных полей для распознавания — само распознавание текста.

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

В первой итерации использовались несколько моделей распознавания:

  • EasyOCR. Для детекции CRAFT + CRNN для распознавания.

  • keras-ocr. CRAFT + CRNN.

  • MMOCR. Модели распознавания SAR, SATRN, RobustScanner, SegOCR, а также разные модели детекции текста в связке с моделями распознавания.

В основе библиотеки EasyOCR (PyTorch), как и в keras-ocr лежат 2 модели: детекции текста CRAFT (Character Region Awareness for Text Detection) и распознавания текста CRNN. Фреймворк MMOCR предлагает намного больше моделей.

Tesseract изначально не рассматривался, так как он хорошо работает с фотографиями высокого разрешения (где могут помочь морфологические операции), что нам не подходит. Также нам нужна высокая скорость обработки на GPU. Хотя Tesseract можно адаптировать под себя, как, например, в статье с исправлением шрифтов, но этот метод не универсален.

Используемые нами модели выдавали в ответ координаты боксов, а также распознанный текст и его score. Из всех моделей выбирался вариант с наибольшим score. Часто фото документов были сделаны под углом, для выравнивания использовался алгоритм Perspective Transformation по 4 координатам бокса. Использовалась и предобработка маски с помощью opencv. Например:

  • Выравнивание гистограммы cv2.equalizeHist.         

  • Расширение изображения dilation:

kernel = np.ones((5,5), np.uint8).
i_im = cv2.dilate(i_im, kernel, iterations=1).
i_im = cv2.normalize(i_im, i_im, 0, 255, norm_type=cv2.NORM_MINMAX)
  • Размытие:

i_im = cv2.GaussianBlur(i_im, (7, 7), 0)
kernel = np.array([[-1,-1,-1], 
                    [-1, 9,-1],
                    [-1,-1,-1]])
i_im = cv2.filter2D(i_im, -1, kernel)
im = cv2.threshold(im, 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]

Для улучшения качества изображения мы пробовали увеличивать разрешение с помощью интерполяции и моделей Super-Resolution. Для правильного определения ориентации маски или фото применяли модель классификации на 4 классах с поворотом на 0, 90, 180, 270 градусов.

Также были попытки обучить на синтетически сгенерированных данных модель CRNN из EasyOCR. Но здесь мы столкнулись с проблемой подбора шрифтов — не удавалось найти один шрифт, чтобы все символы были похожи на символы из оригинальной выборки. Поэтому при генерации синтетических данных мы использовали несколько шрифтов, которые подбирали с помощью онлайн-сервисов (например, WhatTheFont!» MyFonts). 

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

Так как готовые модели были обучены на синтетических датасетах, которые были сгенерированы без большого разнообразия шрифтов и с недостаточной аугментацией, на реальных фото часто путались цифры с буквами (например 6 и G, 7 и T, 2 и Z).

При работе с документами нам часто приходится распознавать определенные последовательности чисел или символов. Поэтому мы решили попробовать character-based метод. Для выделения области распознавания и разделения на символы мы сначала использовали средства opencv. Но не всегда удавалось отделить символы друг от друга, потому что часто документы были измяты или потерты, и исходное фото было в низком разрешении.

В итоге для разделения символов мы начали использовать модель CRAFT. Для Python есть удобная реализация в виде библиотеки craft-text-detector. Библиотека позволяет регулировать параметры выделения текста и получать боксы каждой области текста или символа в отдельности.

Для примера распознаем текст с помощью библиотеки craft-text-detector на кадрах из первого части «Человека-паука» 2002 года:

Оригинальное изображениеОригинальное изображениеText detection boxesText detection boxesText score heatmapText score heatmapLink score heatmapLink score heatmap

Здесь:

  • Text detection boxes — боксы с текстами (которые получаются с помощью работы моделей CRAFT + LinkRefiner).

  • Text score heatmap — вывод модели CRAFT (по каждому символу).

  • Link score heatmap — вывод модели LinkRefiner (модели связи символов).

Чтобы получить char-boxes, а не text-boxes, мы можем выставить значение параметра link_threshold=999999 (сделать большим). Тогда не будет учитываться работа модели связи символов LinkRefiner. Например:

prediction_result = get_prediction(
    image=image,
    craft_net=craft_net,
    refine_net=refine_net,
    text_threshold=0.7,
    link_threshold=999999,
    low_text=0.4,
    cuda=True,
    long_size=1280
)

Char detection boxesChar detection boxes

Более подробный код запуска есть на GitHub. Также с этой библиотекой удобно менять разные пороговые значения. Например, для распознавания более мелких или крупных шрифтов.

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

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

© Habrahabr.ru