Обучаем Tesseract. Tesseract-Ocr в Visual Studio - распознаем страницу текста Оцифровка изображений по одному

Tesseract - свободная платформа для оптического распознавания текста, исходники которой Google подарил сообществу в 2006 году. Если вы пишите софт для распознавания текста, то вам наверняка приходилось обращаться к услугам этой мощной библиотеки. И если она не справилась с вашим текстом, то выход у вас остаётся один - научить её. Процесс этот достаточно сложный и изобилует не очевидными а порой и прям-таки магическими действиями. Оригинальное описание есть . Мне понадобился почти целый день на постижение всей его глубины, поэтому тут я хочу сохранить, надеюсь, более понятный его вариант. Так чтобы помочь себе и другим пройти этот путь в следующий раз быстрее.

0. Что нам нужно

  • Tesseract собственно.
Сборки этой библиотеки есть под windows (можно скачать установщик с официального репозитория) и под linux. Для большинства linux-дистрибутивов установить tesseract можно просто через sudo apt-get install tesseract-ocr , мне для моего модного Еlementary OS пришлось добавить источник:
gedit /etc/apt/sources.list
deb http://notesalexp.net/debian/precise/ precise main
wget -O - http://notesalexp.net/debian/alexp_key.asc
apt-key add alexp_key.asc
apt-get update
apt-get install tesseract-ocr
  • Изображение с текстом для тренировки
Желательно чтобы это был реальный текст, который потом придётся распознавать. Важно, чтобы каждый символ шрифта встречался в сканированном фрагменте не менее 5 раз, а желательно - 20 раз. Формат tiff, без сжатия, желательно не многостраничный. Между всеми символами должны быть чётко различимые промежутки. Кладём наше изображение в отдельную директорию и называем в виде <код языка>.<имя шрифта>.exp<номер>.tif. Изображение может быть не одно и отличаться они должны только номером в наименовании файла. Формат наименований файлов очень важен. На файлы с неверными наименованиями утилиты, которые мы будем использовать будут ругаться ошибками сегментирования и т.п. Для определённости будем считать, что изучаем мы язык ссс и шрифт eee. Таким образом называем файл со сканом тренировочного образца ccc.eee.exp0.tif

1. Создаём и редактируем box-файл
Для того. чтобы отметить символы на изображении и задать их соответствие utf-8 символам текста служат box-файлы. Это обычные текстовые файлы, в которых каждому символу соответствует строка с символом и координатами прямоугольника в пикселях. Первоначально файл генерируем утилитой из пакета tesseract:
tesseract ccc.eee.exp0.tif ccc.eee.exp0 batch.nochop makebox
получили файл ccc.eee.exp0.box в текущей директории. Заглянем в него. Символы в начале строки полностью соответствуют символам в файле? Если это так, то тренировать ничего не нужно, вы можете спать спокойно. В нашем случае скорее всего символы не будут совпадать ни по существу ни по количеству. Т.е. tesseract со словарём по умолчанию не распознал не только символы но и посчитал некоторые из них за два или больше. Возможно часть символов у нас "слипнется", т.е. попадёт в общую коробку и будет распознано как один. Это всё нужно поправить прежде чем идти дальше. Работа нудная и кропотливая, но к счастью для этого есть ряд сторонних утилит. Например я пользовался pyTesseractTrainer-1.03 . Открываем им изображение, box-файл с таким же именем он сам подтянет.
Прошло полдня... Вы с чувством глубокого удовлетворения закрываете pyTesseractTrainer (вы ведь не забыли сохранить результат, верно?) и у вас есть корректный box-файл. Теперь можно переходить к следующему этапу.

2. Тренируем Tesseract
tesseract ccc.eee.exp0.tif ccc.eee.exp0 nobatch box.train
Получаем много ошибок, но ищем в конце что-то вроде "Found 105 good blobs". Если цифра существенно больше числа "изучаемых" символов, то есть шанс, что тренировка в целом удалась. Иначе - возвращаемся в начало. В результате этого шага у вас появился файл ccc.eee.exp0.tr

3. Извлекаем набор символов
unicharset_extractor ccc.eee.exp0.box
Получаем набор символов в виде файла unicharset в текущей директории, где каждый символ и его характеристики располагаются в отдельной строке. Тут нашей задачей будет проверить и поправить характеристики символов (вторая колонка в файле). Для маленьких букв алфавита ставим признак 3, для больших 5, для знаков препинания 10 для цифр 8, всё остальное (типа +=-) помечаем 0. Китайские и японские иероглифы помечаем 1. Обычно все признаки стоят правильно, так что этот этап много времени у вас не займёт.

4. Описываем стиль шрифта
Создаём файл ccc.font_properties с единственной строкой: eee 0 0 0 0 0. Тут вначале пишем имя шрифта, затем числом 1 или 0 помечаем наличие у символов стиля (соответственно italic bold fixed serif fraktur). В нашем случае стилей нет, так что оставляем всё по нулям.

5. Кластеры фигур, прототипы и прочая магия
Для дальнейшей учёбы нам понадобиться выполнить ещё три операции. Можете попробовать понять их смысл из официального описания, мне было не до того:). Просто выполняем:
shapeclustering -F ccc.font_properties -U unicharset ccc.eee.exp0.tr
...появится файл shapetable
а затем:
mftraining -F ccc.font_properties -U unicharset -O ccc.unicharset ccc.eee.exp0.tr
...получим файлы ccc.unicharset, inttemp, pffmtable
и наконец:
cntraining ccc.eee.exp0.tr
...получим файл normproto.

6. Словари
Теоретически заполнение словарей часто используемых слов (и слов вообще) помогает Tesseract-у разбираться в ваших каракулях. Словари использовать необязательно, но если вдруг захочется, делаем файлы frequent_words_list и words_list в которые вписываем (каждое с новой строки) соответственно часто используемые и просто слова языка.
Чтобы сконвертировать эти списки в правильный формат выполняем:
wordlist2dawg frequent_words_list ccc.freq-dawg ccc.unicharset

wordlist2dawg words_list ccc.word-dawg ccc.unicharset

7. Последний загадочный файл
Имя ему - unicharambigs. По идее он должен обратить внимание Tesseract на похожие символы. Это текстовый файл в каждой строке с разделителями табуляцией описываются пары строк, которые могут быть спутаны при распознавании. Полностью формат файла описан в документации , мне он был не нужен и я оставил его пустым.

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

ccc.box
ccc.inttemp
ccc.pffmtable
ccc.tif
ccc.font_properties
ccc.normproto
ccc.shapetable
ccc.tr
ccc.unicharset

И, наконец, выполняем:
combine_tessdata ccc.
(!) Точка обязательна. В результате получаем файл ccc.traineddata, который и позволит нам дальше распознавать наш загадочный новый язык.

9. Проверяем, стоило ли оно того:)
Теперь попробуем распознать наш образец с помощью уже обученного Tesseract-а:
sudo cp ccc.traineddata /usr/share/tesseract-ocr/tessdata/
tesseract ccc.tif output -l ccc
Теперь смотрим в output.txt и радуемся (или огорчаемся, в зависимости от результата).

Если есть готовые решения, нет смысла изобретать костыли и велосипеды. С особым цинизмом это утверждение доказали авторы криптолокера, который для своих целей пользовался CryptoAPI:). Справедливо оно и для решения нашей сегодняшней задачи - расшифровки капчи (с образовательными целями, разумеется). Вперед, запускаем Visual Studio!

Вступление

Весь процесс предстоящей работы можно условно поделить на несколько этапов:

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

В этом нам помогут:

  • AForgeNet - библиотеки компьютерного зрения и искусственного интеллекта;
  • Tesseract - программа для распознавания текстов;
  • Fanndotnetwrapper - обертка.NET нейросети FANN;
  • алгоритм поиска связанности CCLA от Omar Gameel Salem.

Исходник на dvd.сайт

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

Подготовительный этап

Запускаем Visual Studio и создаем новый оконный проект на языке C#. Откроем его в проводнике, для того чтобы скопировать туда требуемые файлы.


Для обучения нейросети FANN использована часть кода из Tesseract, отличие заключается в том, что мы создаем один текстовый файл train.tr, в котором первая строка - количество картинок, количество точек в каждой (ширина, умноженная на высоту) и количество выходов (букв, которые мы ищем). Сама картинка до всего этого проходит обязательную бинаризацию, для того чтобы выделить всего два состояния каждой точки (1 - черный, 0 - белый цвет), и сохраняется далее в этом же файле во всех следующих строках. Для удобства и возможности использовать разные заранее созданные обученные ann-файлы был создан дополнительный текстовый файл CONFIG.txt. Он состоит из одной строки и указывает количество точек и выходов с их значениями, случайно запустить проверку captcha на другом ann-файле не получится.

String a = File.ReadAllText(SaveFilesPath + "CONFIG.txt"); string b = a.Split(" "); int SumPix = Convert.ToInt32(b); int Outpt = Convert.ToInt32(b.Length); uint layers = { (uint)SumPix, (uint)layerS, (uint)Outpt }; net.CreateStandardArray(layers); net.RandomizeWeights(-0.1, 0.1); net.SetLearningRate(0.7f); TrainingData data = new TrainingData(); data.ReadTrainFromFile(SaveFilesPath + "train.tr"); net.TrainOnData(data, 1000, 0, 0.001f); net.Save(SaveFilesPath + "FANNLearning.ann");

Получаем конфиг, читаем параметры, число слоев (layers) по рекомендации Википедии задано равным 120, все остальное было выбрано случайным образом или подсмотрено в Сети. Скорость обучения зависит от мощности твоего железа и того, что написано выше. Например, i7-4702MQ при 6500 картинок одним ядром был занят минут 20–30.

Шаг шестой. Распознавание

В заключительном этапе реализовано два подхода, но используется тот, обучение которого было проведено. Tesseract 3.02 и FANN находятся в нижней левой части главного окна. Первый умеет искать по английскому (выбираем символы из выпадающего списка), русскому, Math и словарю пользователя. Поиск словаря происходит автоматически, и в подсказке tooltip высвечиваются все доступные. Второй распознает текст по кнопке FANNOCR и выводит в лог (левая часть окна) результат анализа для каждого выбранного символа. Очень удобно смотреть, почему нейронная сеть выбрала тот или иной выход. Рассмотрим, как это работает в случае нейронной сети.

Private string OCR(Bitmap img) { ... { int whx = img.Width * img.Height; if (SUMMPIX != whx) { /* Выводим ошибку, не сошлось количество пикселей */} double input = GetPix(img); double result = net.Run(input); if (tempanswer.Length != result.Length) { /* Выводим ошибку, разное количество выходов */} int maxN = FindMax(result); answer = Convert.ToString(tempanswer); if (ToLogEvent != null) ToLogEvent(result, tempanswer, answer); ... } }

Получили картинку от public-метода, где реализован net.CreateFromFile(SaveFilesPath + "FANNLearning.ann") и чтение конфиг файла, tempanswer - это переменная, равная b, в ней перечислены буквы, которые мы ищем. Сравниваем число пикселей, записываем их в массив и прогоняем через обученный ann, выискивая максимально высокий процент совпадения, затем направляем результат в событие, выбрав один выход и получив букву, закрепленную за ним.

Обсуждаем результаты

Мои результаты тестирования сильно зависели от количества и качества картинок для обучения, а в случае с нейросетью FANN - и от количества выходов тоже. В среднем captcha, поддавшаяся фильтрам, имела ~80% правильного распознавания, тут многое зависит от усидчивости и желания - чему научишь, то и получишь. Главное - это работает.

Заключение

Все описанное в статье можно применить для решения многих других задач. Например, мне при поиске информации для статьи повстречался подробный разбор распознавания образа автомобиля на стоянке. Включай фантазию и Visual Studio! 🙂

В статье рассматривается процедура обучения русскому языку открытой OCR-системы Tesseract, разрабатываемой комапнией Hewlett-Packard.

[Власов Игорь (igorvlassov at narod dot ru)]

Искал я тут давеча OCR для одного англоязычного проекта. И попутно ознакомился с состоянием дел относительно родного языка. Свободной OCR, способной распознавать родную речь, я не обнаружил. Зато наткнулся на проект tesseract. Это бывшая коммерческая многоплатформенная OCR, разработанная Hevlet Packard. Теперь она, во-первых, распространяется под лицензией Apache v.2. А во-вторых, ее можно попытаться обучить какому-нибудь новому языку, что мы и попробуем сделать. Итак, читаем мануал под названием TrainingTesseract:

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

При подготовке тренировочного файла надо помнить следующее:

    требуется минимальное количество примеров каждого символа. 10 - хорошо, но 5 - достаточно для редких символов, а для часто встречающихся надо хотя бы 20;

    нельзя группировать небуквенные символы все вместе, надо делать текст более реалистичным, например:
    в чащах юга жил-был цитрус да но фальшивый экземпляр . 0123456789 !@#$%^&(),.{}<>/? - ужасно. Гораздо лучше: в чащах {юга} жил-(был) цитрус, да! но? <фальшивый> $3456.78 экземпляр #90 /помидор" 12.5%

    неплохо бы растянуть текст с помощью увеличения межстрочного и межсимвольного интервалов;

    тренировочные данные должны умещаться на одной странице;

    нет необходимости тренироваться на нескольких размерах, достаточно на шрифте размером 10. Но для высоты текста меньше 15 пикселов нужно тренировать отдельно или увеличить изображение до распознавания.

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

Я попробую сделать это только для шрифта Thorndale AMT, который на моем десктопе под SUSE10 в OpenOffice выглядит почти как Times New Roman под Виндой. Итак, делаю отдельный файлик с выше приведенным текстом про цитрус fontfile.odt, печатаю, сканирую и сохраняю в черно-белый BMP fontfile.bmp.

Следующий шаг - это создание файла с координатами прямоугольников, в которых заключен каждый символ. К счастью, tesseract может сделать файл требуемого формата, хоть набор символов и не будет соответствовать нашему. Поэтому потом надо будет поправить файл вручную, введя правильные символы. Итак, делаем:

tesseract fontfile.bmp fontfile batch.nochop makebox

В результате получился файл fontfile.txt, который надо переименовать в fontfile.box

Вот что у меня там:

M 85 132 111 154

Z 114 137 130 154

X 133 137 150 154

{ 170 130 180 162

m 186 137 210 154

r 214 137 228 154

a 233 137 248 154

} 254 130 264 162

M 284 137 306 154

Теперь самая суровая часть - надо этот файлик отредактировать в редакторе, в котором можно заменить неправильные символы на нужные. Я использую Kate.

Опс, похоже, щ заменилось 2-мя символами:

M 85 132 111 154

в этом случае надо объединить описывающие прямоугольники следующим образом:

    Первый номер (левый) должен быть минимальным из 2-х строк (67)

    Второй номер (низ) должен быть минимальным из 2-х строк (132)

    Третий номер (правый) должен быть максимальным из 2-х строк (111)

    Четвертый номер (верх) должен быть максимальным из 2-х строк (154)

итак: щ 67 132 111 154

Замечание: координатная система, используемая в этом файле, начинается с (0,0) и направлена снизу вверх и слева направо.

Фух, кажется, поправил. Теперь запускаем tesseract в обучающем режиме:

tesseract fontfile.bmp junk nobatch box.train

и смотрим stderr (или tesseract.log под Виндой). Если есть ошибки вида FATALITY,

это значит что tesseract не нашел ни одного образца символа, указанного в координатном файле. У меня он выдал ошибку:

APPLY_BOXES: FATALITY - 0 labelled samples of "%" - target is 2

Boxes read from boxfile: 89

Initially labelled blobs: 87 in 3 rows

Box failures detected: 2

Duped blobs for rebalance: 0

"%" has fewest samples: 0

Total unlabelled words: 1

Final labelled words: 87

Generating training data

TRAINING ... Font name = UnknownFont.

Generated training data for 87 blobs

Однако fontfile.tr сгенерился. Ладно, обойдусь пока без знака % Вообще надо было сделать побольше всех символов, хотя бы повторить эту фразу пяток раз.

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

mftraining fontfile_1.tr fontfile_2.tr ...

в результате должны получиться 2 файла: inttemp (прототипы форм) и pffmtable , затем

cntraining fontfile_1.tr fontfile_2.tr ...

создаст normproto файл (прототипы для нормализации символов?).

Делаю это над одним моим файлом. Что-то получилось. Теперь надо указать tesseract"у множество символов, которое он может вывести. Используем команду unicharset_extractor чтобы сгенерить файл unicharset:

unicharset_extractor fontfile_1.box fontfile_2.box ...

Делаем. В полученном файле необходимо указать тип символа с помощью маски, маска такая: если буква - 1, если маленькая буква - 1, если большая буква - 1, если цифра -1, иначе 0.

Например,

б - маленькая буква. Еее маска 0011 или шестнадцатеричная 3

; - не буква, не цифра. Маска = 0

7 - просто цифра. Маска 1000 или шестнадцатеричная 8.

Ь - большая буква. Маска 0101 или шестнадцатеричная 5

у меня все буквы маленькие. Меняю им маску на 3.

Теперь надо где-то взять два списка, один - часто встречающихся слов, второй - остальных слов и преобразовать их в DAWG-формат с помощью еще одной утилитки:

wordlist2dawg frequent_words_list freq-dawg

wordlist2dawg words_list word-dawg

Я для начала просто набил в каждый по 5 произвольных слов.

Третий файл, user-words обычно пустой.

Последний файл, который надо сделать, называется DangAmbigs В нем описываются случаи ошибочной замены одного файла на другой, например

первая цифра - количество символов в первой группе, 2-я - кол-во символов во 2-й.

Эта строка показывает, что 1И может иногда распознаваться неправильно как Ш.

Этот файл тоже м.б. пустым.

Теперь все собираем вместе. Файлы

    freq-dawg

    word-dawg

    user-words

    inttemp

    normproto

    pffmtable

    unicharset

    DangAmbigs

снабжаем префиксом rus и помещаем в туда, где остальные словари, у меня это /usr/local/share/tessdata

Все!!!

Пробуем распознать какой-нибудь файлик. Я попробую для начала свой про цитрус:

tesseract image.bmp output -l rus

Вот что у меня получилось:

в чыаьах {юга} жшл-(был) цштрус, да! но?

<(1ьалвьшвый> $3456.78 экземпляр #90

капелвсшнм/помшдор" 12.5й

Конечно, не супер, но для первого раза, и столь скудных образца и словаря, я думаю, неплохо!

Власов Игорь (igorvlassov at narod dot ru) - Tesseract по-русски

Tesseract-ocr - свободная библиотека для распознавания текста. Для того, чтобы ее подключить необходимо скачать следующие компоненты:
Leptonica - http://code.google.com/p/leptonica/downloads/detail?name=leptonica-1.68-win32-lib-include-dirs.zip
Последнюю версию tesseract-ocr (на данный момент 3.02) - https://code.google.com/p/tesseract-ocr/downloads/detail?name=tesseract-3.02.02-win32-lib-include-dirs.zip&can=2&q=
Данные обучения русскому языку - https://tesseract-ocr.googlecode.com/files/tesseract-ocr-3.02.rus.tar.gz
Все можно собирать самостоятельно, скачав исходные коды, но мы этим заниматься не будем.

Создав новый проект, подключаем пути до lib и h файлов. И пишем простенький код.
#include #include int main() { tesseract::TessBaseAPI *myOCR = new tesseract::TessBaseAPI(); printf("Tesseract-ocr version: %s\n", myOCR->Version()); printf("Leptonica version: %s\n", getLeptonicaVersion()); if (myOCR->Init(NULL, "rus")) { fprintf(stderr, "Could not initialize tesseract.\n"); exit(1); } Pix *pix = pixRead("test.tif"); myOCR->SetImage(pix); char outText; lstrcpy(outText, myOCR->GetUTF8Text()); printf("OCR output:\n\n"); printf(outText); myOCR->Clear(); myOCR->End(); pixDestroy(&pix); return 0; }

Подключаем lib-файлы:
libtesseract302.lib
liblept168.lib

Компилируем - программа успешно создается. В качестве примера возьмем следующую картинку:

Запускаем программу, чтобы информация вывелась в файл (поскольку UTF-8 в консоли хаос будет):
test > a.txt

Содержимое файла ниже:
Tesseract-ocr version: 3.02
Leptonica version: leptonica-1.68 (Mar 14 2011, 10:47:28)
OCR output:

‚Подставив это выражение в (63), видим, что оги-
бающая однополосного ‚сигнала промодулирована
и глубина модуляции равна а.
7 Огибающую ХО) первичного сигнала непосред-
ственно на осциллографе наблюдать нельзя, так у
‚ как этот сигнал ие является узкополосным, а вэтом
‘случае «наглядность» огибающей отсутствует, Но
при однополосной модуляции формируется узкопо-
‘лосный сигнал с той же огибающей, и тут-то она
«и проявляется в явном виде и иногда (как в опи-
„санном случае) вносит смятение в умы малоопыт-
и ных исследователей..
6,4. «ФОРМУЛА КОСТАСА»
г у
С появлением ОМ в учебниках, журнальных `
Ёстатьях и монографиях дебатировался вопрос о
том, какой выигрыш дает переход от амплитудной
модуляции к однополосной. Было высказано много ‚
разноречивых мнений. Вначале 60-х годов аме-
риканский ученый Дж. Костас писал, что, просмо-
трев обширную журнальную литературу по ОМ, он
обнаружил в каждой статье свою оценку энергети-
“ческого выигрыша относительно АМ-от двух до,
нескольких десятков. В результате он установил,
-что выигрыш, указываемый в каждой статье, со-
ставляет примерно (З-К-Ы!) дБ, где М-число со- ‘ г
› авторов данной статьи.
Ё,‘ 11 Если эта шутка и неточна, она все же правиль-
‘нот отражает тот разнобой, который существовал
; в те годы. Помимо того, что разные авторы произ-
Д водили сравнение в различных условиях и по-раз-м
‚ ‚ному определяли энергетический выигрыш, они так- 1
‘‚ `же допускали немало различных ошибок. 4 "
‚` Вот примеры некоторых рассуждений. ",
1. При обычной АМ, полагая мощность’ несущей

Публикации по теме