Как стать автором
Обновить

Python + OpenCV + Keras: делаем распознавалку текста за полчаса

Время на прочтение 12 мин
Количество просмотров 197K
Всего голосов 37: ↑35 и ↓2 +33
Комментарии 27

Комментарии 27

Хорошо сделано! В закладки!
Спасибо.

Если кто-то знает базу печатных символов (не рукописных), было бы интересно переобучить модель на ней.

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

Лень же. 100% уверен что кто-то уже это делал.

Либо да, наверно уже скрипт есть, который все системные шрифты переберет и сгенерит базу символов.
А я по простому делал) Просто скопировал все шрифты в системе в папку с проектом и далее в питоне есть способ итерировать списку list_fonts = os.listdir('.'). Правда, не все шрифты подходят для кирилицы, так что пришлось часть удалить. Но все равно, сетка уверенно научилась распознавать. Еще всякие агментации делал, чтобы усложнить задачу.
Спасибо. Думаю, даже если взять просто 10 самых популярных экранных шрифтов, будет уже достаточно. Да и ключевые признаки букв нейросеть дальше «сама» подхватит.

Но у меня не было цели доводить все это до завершенного продукта, так что не знаю, буду ли заморачиваться. Следующим шагом интересно распознавание слов попробовать и более сложные методики работы с текстом.
Чтобы не путать символы с идентичным написанием надо или словари использовать, или обучать/применять сеть не на буквах, а на словах, то есть ещё добавить ещё RNN или CNN поверх фичемап до выходов классификации отдельных символов (выходы отдельных символов тоже можно на обучении использовать).
Спасибо, как-нибудь попробую.
НЛО прилетело и опубликовало эту надпись здесь
Привет! Ты на мой коммент специально ответил или полем промахнулся?.. Я тут в одном проекте Class Activation Maps для semi-supervised object detection пытаюсь абъюзить, так что про FindContours это точно не ко мне :-).
В базе EMNIST русских букв все равно нет, так что не проверял.

Да, на сканах подход с findContours может плохо работать.

В английском языке есть буквы i, j с разрывным контуром

В коде текст сначала увеличивается, потом от него берется контур.



C i/j это работает, с Ы уже не факт (не проверял). В идеале, нужен отдельный более интеллектуальный алгоритм разбиения на буквы.
Только я так понял вы не масштабируете буквы, а дополняете до квадратика полями?
И то и то. Сначала дополняю, потом масштабирую — нейросети на вход нужны картинки 28x28.
Ну что квадратик масштабируете это понятно, просто я бы понял фразу, что каждую букву нужно растянуть до квадратика.
Да, сначала нужно дополнить canvas size до квадрата (а не просто растянуть, иначе буква исказится), затем уже масштабировать в 28х28.

Может в тексте это не так очевидно, но код же выложен :)
Не будет ли лучше распознавать сеть, обученная на растянутых символах, т.к. там наверное всё таки больше информации остаётся нежели в случае, если мы добиваем белыми пикселями, а полезную часть квантуем меньшим числом пикселей?
Хотя наверное распознавание 0 и О только ухудшится…
Информация не теряется, буква просто дополняется до квадрата, она сама никуда не пропадает, ну и большинство букв не квадратные обычно :)

Распознавать искаженные буквы имхо нет смысла, если «I» растянуть до квадрата, получится квадрат Малевича, нисколько не похожий на оригинал.
Так не надо быть похожим на оригинал, надо быть похожим на квадрат малевича которому обучили.
Т.е. при квантовании, например, 100 исходных пикселей 10 и 28 пикселями одна и та же информация остаётся?
Исходная база, по которой обучалась нейросеть, содержит нормальные, не растянутые буквы, так что и подавать на вход нейронной сети надо тоже нормальные, тут все просто.
Вы же сами сказали, что нужна своя база для обучения…
Да, если обучать нейросеть на изначально растянутых буквах, и потом подавать такие же, то работать будет. Но зачем? От растяжения буквы до квадрата дополнительной информации в ней не появится, так что плюсов не я вижу.
Если изначально было полтора пикселя на букву, то не появится, а так можем не потерять инфу при сжатии до 28 пикселей.
Для букв на самом деле некритично, там совсем мелкие завитушки и не нужны, они скорее наоборот даже мешать будут. А вот например картинки автомобилей/животных размером 32х32 в датасете CIFAR 10 это жесть.

PS: Если распознавать китайские иероглифы, то может 28х28 и не хватит. Но тут я не спец, не знаю :)
Сам недавно занимался распознаванием печатного текста с фотографии и рукописных цифр.
Потому могу порекомендовать использовать для распознавания печатных букв Tesseract, а OpenCV можно использовать для предварительной обработки изображения – удаление шумов, выделение контуров. Внутри Tesseract 4 также есть нейронная сеть, обученная на большом количестве шрифтов. Есть версии разного качества для различных языков, в т.ч. и для русского.

Что касается MNIST, – он тоже работает только в тепличных условиях. Я использовал обученную модель LightGMB, которая имеет точность ~98.5% на тестовых данных, но при этом не распознает цифры с реальных фотографий. Причина в том, что мало подогнать цифру под размер 28*28, нужно сделать дополнительную обработку изображения, а именно – сжать цифру до 20*20 пикселей, а потом сместить от центра в направлении, противоположном центру массы изображения. Это сложно объяснить на пальцах, но такой подход повышает точность в несколько раз. Есть ли подобная проблема у EMNIST, мне неизвестно.

P.S. Еще известная проблема MNIST заключается в том, что он собран на данных америкосов, если посмотреть на картинки, то можно увидеть, что некоторые цифры они пишут совсем не так, как нас учили в школе. Это также ощутимо влияет на качество распознавания этих цифр.
Интересно, конечно, для ввода в тему, но плохо то, что статья не ориентирована на реальный выхлоп. Да, «делать второй FineReader» не нужно, но FineReader рассчитан на профессиональную работу с документами, а, скажем, для распознавания встроенных титров в видео, например, обучающих, типа «Easy French» ( www.youtube.com/watch?v=bb4zvZdrMz4 ), он не годится.

А так, идея обучающих видео очень классная. Если допустим в указанном ролике затереть английский перевод и добавить русский (хоть встроенными субтитрами, хоть обычными), то было бы просто супер. Конечно, можно непосредственно подключить переводные субтитры на русском языке, но получается не слишком изящно. Распознавание голоса, даже на Ютубе, пока еще не идеально. В любом случае, распознавание встроенных оригинальных субтитров в видео, думаю, вполне востребовано. Бывают обучающие ролики с очень мелкими встроенными субтитрами, а автоматические текстовые субтитры, как правило, оставляют желать лучшего. Там было бы удобно распознать оригинальный встроенный текст, затереть его и вывести (внутренним либо внешним образом) в виде более крупного шрифта и даже другим цветом. Иногда и ошибки можно исправить.

Я не предлагаю вам всем этим заниматься. Я сам сейчас этим занимаюсь, и если что-то получится, то напишу свою статью, здесь, на хабре.

Но уже могу сказать, что французский текст именно этого ролика вполне уверенно распознается моей достаточно простой программой на с++ (без машинного обучения и соответствующих баз данных). Причем, ошибки распознавания легко корректировать. Увидел не узнанный символ, посмотрел его параметры, внес небольшие корректировки в код и вуаля, следующий перевод уже без ошибок. Пока это все делается на уровне отдельных кадров, а нужно на уровне всего видео.

Интересно, но сцепленные символы, сдвоенные и даже строенные (допускаю и большее количество) тоже легко настраивать на распознавание. Например, строенными тут идут символы «st-» (между ними нельзя провести прямые разделительные линии, хотя бы из-за дефектов изображений). А сдвоенных пар гораздо больше: «nj», «ra», «ve», «et», «to», и множество других, даже «r.» сцеплены.

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

Публикации

Истории