Обучаем Tesseract. Tesseract-Ocr в Visual Studio - распознаем страницу текста Оцифровка изображений по одному
Tesseract - свободная платформа для оптического распознавания текста, исходники которой Google подарил сообществу в 2006 году. Если вы пишите софт для распознавания текста, то вам наверняка приходилось обращаться к услугам этой мощной библиотеки. И если она не справилась с вашим текстом, то выход у вас остаётся один - научить её. Процесс этот достаточно сложный и изобилует не очевидными а порой и прям-таки магическими действиями. Оригинальное описание есть . Мне понадобился почти целый день на постижение всей его глубины, поэтому тут я хочу сохранить, надеюсь, более понятный его вариант. Так чтобы помочь себе и другим пройти этот путь в следующий раз быстрее.
0. Что нам нужно
- Tesseract собственно.
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
- Изображение с текстом для тренировки
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
Подключаем 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. При обычной АМ, полагая мощность’ несущей