Pull to refresh
249.96
Инфосистемы Джет
российская ИТ-компания

OCR за час? — Не думаю

Reading time4 min
Views14K

О задаче

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

Предполагалось, что если повернуть брусок так, чтобы номер располагался горизонтально, это поможет распознаванию. Один из возможных вариантов поворота придумать несложно, об этом ниже. Но глобально задача предполагала именно распознавание. Ранее задачами OCR глубоко я не занимался, и мне стало интересно, на что способны имеющиеся коробочные решения. Казалось бы, они должны легко решить нашу задачу за час. О том, что было на самом деле, и пойдет речь в этой статье.

Paddle OCR

Одним из самых популярных репозиториев на Github и Papers With Code является PaddleOCR. Обычно OCR-пайплайны сначала детектируют области с текстом, а потом, с помощью так называемого recognizer’a, извлекают текст. PaddleOCR тут не исключение. Единственное усложнение - добавление классификатора ориентации текста после детекции, что позволяет модели отрабатывать на текстах с ориентацией, кратной \pi/2 (Рисунок 1).

Рисунок 1. Cхема работы PaddelOCR (Github).
Рисунок 1. Cхема работы PaddelOCR (Github).

Сразу перейдем к примерам:

Рисунок 2. Пример с вертикально ориентированным номером (размер 450х523).
Рисунок 2. Пример с вертикально ориентированным номером (размер 450х523).

Например, на такой картинке (Рисунок 2) PaddleOCR отлично справился с распознаванием номера 84612000 (confidence 0.98), а 281 не нашел вообще.

Рисунок 3. Пример с наклонным углом (размер 603х600).
Рисунок 3. Пример с наклонным углом (размер 603х600).

А вот на этом изображении (Рисунок 3) нашел:

  • ('612', 0.988)(значение в кавычках - распознанный текст, число рядом - confidence модели, далее результаты распознавания буду предоставлять в таком формате);

  • ('C', 0.902);

  • ('*8', 0.834).

Получаем лишь куски номеров или вовсе не то, что нужно.

Поворачиваем текст

Окей, PaddleOCR не завелся идеально из коробки, пришлось поворачивать бруски. Идейно подход такой:

  • сегментируем область с номером, получаем маску. Нестрого говоря, она имеет вид эллипса - то есть вытянута вдоль одной из осей.

  • Далее через точки маски строится линейная регрессия.

  • Зная коэффициент наклона прямой, находим угол поворота.

Рисунок 4. Схема алгоритма поворота надписи.
Рисунок 4. Схема алгоритма поворота надписи.

Тест Open Source решений

Для примера в статье возьму часть фотографии, на которой PaddleOCR не отработал, а именно часть фотографии с номером 281 (Рисунок 5)

Рисунок 5. Часть фотографии после поворота (размер 367x180).
Рисунок 5. Часть фотографии после поворота (размер 367x180).

Подход №1. "В лоб"

  • PaddleOCR
    Тестируем PaddleOCR на повернутом тексте. Ничего не обнаруживается. Кстати, расположение текста мы уже "детектировали" с предыдущего этапа с поворотом номера и возникает вопрос: может быть детектор косячит, и попробовать отдать номер сразу в recognizer?

    Окей, recognizer что-то распознал, но на номер это не похоже: ('HEi', 0.567).

  • Tesseract
    Возьмем представителя старой школы - Tesseract (python wrapper).
    Ожидаемо, он справляется не очень хорошо - ничего не видит.

    И действительно, Tesseract довольно требователен к входным данным, есть даже отдельный раздел в документации по улучшению данных на входе.

  • EasyOCR

    Рисунок 6. Схема работы EasyOCR (Github).
    Рисунок 6. Схема работы EasyOCR (Github).

EasyOCR использует в качестве детектора текста CRAFT, а в качестве recognizer'a - ResNet50 + LSTM + CTC Loss. Реализовано все на PyTorch. Надо сказать, что документации у EasyOCR простая и понятная, а recognizer довольно просто дообучить на своих данных.

Но вернёмся к результату на нашем примере. EasyOCR находит что-то более осмысленное:

  • С детектором видит ('201', 0.728);

  • Без детектора ('3281', 0.237) - нашел даже больше, чем надо.

Замечу, что с настройками по умолчанию, EasyOCR производит вычисления для 4 изображений, повернутых на 0, 90, 180 и 270 градусов. Можно задать свои настройки для углов поворота. Если вы уверены, что текст ориентирован горизонтально,можно указать лишь один угол для экономии времени.

Подход №2. Бинаризация

Как оказалось, для моделей OCR довольно сложно распознавать текст, имеющий сложную форму и структуру (у нас символы состоят из светлых и темных частей за счет преломления света) на произвольном фоне. Попробуем избавиться от фона и минимизировать переливы света на выбитых цифрах за счет бинаризации фотографии. Для примера возьмем всё то же изображение.

Рисунок 7. Рисунок 5 после бинаризации.
Рисунок 7. Рисунок 5 после бинаризации.
  • PaddleOCR
    А вот на бинаризованной фотографии paddle отработал исправно - ('281', 0.964)
    Recognizer без детектора нашел только ('t', 0.541)

  • Tesseract
    Still nothing.

  • EasyOCR
    EasyOCR с детектором тоже справился - ('281', 0.983)
    А вот без детектора все еще находит лишнее - ('7281', 0.396) (возможно, потому что на нашей фотографии 2 сильно похожа на 7)

Подход №2.1 Инвертированние

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

Рисунок 8. Инвертированный рисунок 7.
Рисунок 8. Инвертированный рисунок 7.

Ниже в таблице приведены результаты моделей на рисунках 6-8.

Таблица 1. Результаты из подходов №1, №2, №2.1.

Модель

Результат подхода №1

Результат подхода №2

Результат подхода №2.1

PaddleOCR

_

('281', 0.964)

('8 2', 0.823)

PaddleOCR (recognizer only)

('HEi', 0.567)

('t', 0.541)

('zal', 0.409)

Tesseract

-

-

-

EasyOCR

('201', 0.728)

('281', 0.983)

('8281', 0.354)

EasyOCR (recognizer only)

('3281', 0.237)

('7281', 0.396)

('7281', 0.199)

Telegram OCR

Казалось, что современные open source решения должны отрабатывать более стабильно. Поэтому, немного разочаровавшись в результатах, мы решили протестить OCR, встроенный в какое нибудь приложение. Как оказалось, в Telegram для iOS есть встроенный OCR, о котором узнали случайно, просто пересылая фотографию. Загрузили нашу картинку в "телегу" и опа! - он нашел "281" и для оригинальной фотографии, и для бинаризованной версии, а вот для инвертированной версии тоже выдал нечто - "2. 8 Fa" (хотя с "2. 8" можно согласиться).

Выводы и варианты улучшения распознавания

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

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

  • Скорее всего, модели в обучающей выборке видели не очень много выдавленных в металле цифр, и fine tuning моделей должен сильно улучшить результаты - эксперимент с бинаризацией это подтверждает. C другой стороны, Telegram справился, то есть существуют модели, которые "могут".

  • Возможно, для конкретно такой задачи использованные модели OCR это overkill и следует использовать детекцию каждой отдельной цифры.

Tags:
Hubs:
Total votes 31: ↑30 and ↓1+29
Comments7

Articles

Information

Website
jet.su
Registered
Founded
1991
Employees
1,001–5,000 employees
Location
Россия