Tesseract обучение. Обучаем Tesseract

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 и радуемся (или огорчаемся, в зависимости от результата).

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. При обычной АМ, полагая мощность’ несущей

Понадобилось мне получить значения забитмапленных чисел. Числа грабились с экрана.

Я подумал, а не попробовать ли мне OCR? Попробовал Tesseract .

Ниже я расскажу как я пытался приспособить Tesseract, зачем я его тренировал, и что из этого получилось. В проекте на гитхабе лежит cmd-скрипт, автоматизирующий насколько возможно процесс тренировки, и данные, на которых я проводил тренировку. Словом, есть все что нужно, чтобы с места в карьер обучить Tesseract чему-нибудь полезному.

Подготовка

Клонируем репозитарий или скачиваем zip-архив (~6Mb). Устанавливаем tesseract 3.01 с оф.сайта . Если его там уже нет, то из подкаталога zip-архив/distros.

Переходим в папку samples, запускаем montage_all.cmd
Этот скрипт создаст итоговое изображение samples/total.png , можно скрипт не запускать, т.к. я уже поместил его в корневую папку проекта.

Зачем тренировать?

Быть может и без тренировки результат будет хороший? Проверим.
./exp1 - as is> tesseract ../total.png total

Поместим исправленный результат в файл model_total.txt , чтобы сравнивать с ним результаты распознаваний. Звездочка маркирует неправильные значения.

model_total.txt Распознавание
по умолчанию
27
33
39
625.05
9
163
1,740.10
15
36
45
72
324
468
93
453
1,200.10
80.10
152.25
158.25
176.07
97.50
170.62
54
102
162
78
136.50
443.62
633.74
24
1,579.73
1,576.73
332.23
957.69
954.69
963.68
1,441.02
1,635.34
50
76
168
21
48
30
42
108
126
144
114
462
378
522
60
240
246
459.69
456.69
198
61
255
27
33
39
525 05*
9
153*
1,740 10*
15
35*
45
72
324
455*
93
453
1,200 10*
50 10*
152 25*
155 25*
175 07*
97 50*
170 52*
54
102
152*
75*
135 50*
443 52*
533 74*
24
1,579 73*
1,575 73*
332 23*
957 59*
954 59*
953 55*
1,441 02*
1,535 34*
50
75*
155*
21
45*
30
42
105*
125*
144
114
452*
375*
522
50*
240
245*
459 59*
455 59*
195*
51*
255

ошибки распознавания по умолчанию

Видно, что ошибок много. Если приглядеться, то можно заметить, что не распознается десятичная точка, цифры 6 и 8 распознаются как 5. Поможет ли тренировка избавиться от ошибок?

Тренировка

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

Чтобы выполнить тренировку надо запустить./exp2 - trained> train.cmd

В чем заключается процесс тренировки? А в том, что tesseract обрабатывает тренировочное изображение и формирует т.н. боксы символов - выделяет из текста отдельные символы создавая список ограничивающих прямоугольников. При этом он делает догадки относительно того, какой именно символ ограничен прямоугольником.

Результаты этой работы записывает в файл total.box, который выглядит так:
2 46 946 52 956 0
7 54 946 60 956 0
3 46 930 52 940 0
3 54 930 60 940 0
3 46 914 52 924 0
9 53 914 60 924 0
6 31 898 38 908 0
2 40 898 46 908 0
5 48 898 54 908 0
0 59 898 66 908 0

Здесь в певом столбце символ, а в 2 - 5 столбцах координаты левого нижнего угла прямоугольника, его высота и ширина.

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

После запуска./exp2 - trained> java -jar jTessBoxEditor-0.6jTessBoxEditor.jar надо открыть файл./exp2 - trained/total.png , при этом будет автоматически открыт файл./exp2 - trained/total.box и определенные в нем прямоугольники будут наложены на тренировочное изображение.

В левой части приведено содержимое файла total.box, справа расположено тренировочное изображение. Над изображением расположена активная строка файла total.box

Синим изображены боксы, а красным - бокс, соответствующий активной строке.

Я исправил все неправильные 5-ки на правильные 6-ки и 8-ки, добавил строки с определениями всех десятичных точек, имеющихся в файле и сохранил total.box

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

Чтобы использовать результаты обучения при распознавании надо запустить tesseract c ключом -l ttn
./exp2 - trained/> tesseract ../total.png total-trained -l ttn

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

model_total.txt Распознавание
по умолчанию
Распознавание
после тренировки
27
33
39
625.05
9
163
1,740.10
15
36
45
72
324
468
93
453
1,200.10
80.10
152.25
158.25
176.07
97.50
170.62
54
102
162
78
136.50
443.62
633.74
24
1,579.73
1,576.73
332.23
957.69
954.69
963.68
1,441.02
1,635.34
50
76
168
21
48
30
42
108
126
144
114
462
378
522
60
240
246
459.69
456.69
198
61
255
27
33
39
525 05*
9
153*
1,740 10*
15
35*
45
72
324
455*
93
453
1,200 10*
50 10*
152 25*
155 25*
175 07*
97 50*
170 52*
54
102
152*
75*
135 50*
443 52*
533 74*
24
1,579 73*
1,575 73*
332 23*
957 59*
954 59*
953 55*
1,441 02*
1,535 34*
50
75*
155*
21
45*
30
42
105*
125*
144
114
452*
375*
522
50*
240
245*
459 59*
455 59*
195*
51*
255
27
33
39
625 05*
9
163
1,740 10*
15
36
45
72
324
468
93
453
1,200 10*
80 10*
152 25*
158 25*
176 07*
97 50*
170 62*
54
102
162
78
136 50*
443 62*
633 74*
24
1,579 73*
1,576 73*
332 23*
957 69*
954 69*
963 68*
1,441 02*
1,635 34*
50
76
168
21
48
30
42
108
126
144
114
462
378
522
60
240
246
459 69*
456 69*
198
61
255

ошибки распознавания с обучением

Увеличение изображения

Увеличивать можно по-разному, я попробовал два способа: scale и resize

total-scaled.png (фрагмент) total-resized.png (фрагмент)
convert total.png total-scaled.png -scale "208x1920" convert total.png total-resized.png -resize "208x1920"

Так как изображения символов увеличились вместе с самими изображениями, данные тренировки под кодом ttn устарели. Поэтому дальше я распознавал без ключа -l ttn.

Видно, что на изображении total-scaled.png tesseract путает 7-ку с 2-кой, а на total-resized.png не путает. На обоих изображениях корректно определяется десятичная точка. Распознавание изображения total-resized.png почти идеально. Есть только три ошибки - пробел между цифрами в числах 21, 114 и 61.

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

ошибки распознавания total-scaled.png

ошибки распознавания total-resized.png

model_total.txt Распознавание
по умолчанию
Распознавание
после тренировки
total-scaled.png total-resized.png
27
33
39
625.05
9
163
1,740.10
15
36
45
72
324
468
93
453
1,200.10
80.10
152.25
158.25
176.07
97.50
170.62
54
102
162
78
136.50
443.62
633.74
24
1,579.73
1,576.73
332.23
957.69
954.69
963.68
1,441.02
1,635.34
50
76
168
21
48
30
42
108
126
144
114
462
378
522
60
240
246
459.69
456.69
198
61
255
27
33
39
525 05*
9
153*
1,740 10*
15
35*
45
72
324
455*
93
453
1,200 10*
50 10*
152 25*
155 25*
175 07*
97 50*
170 52*
54
102
152*
75*
135 50*
443 52*
533 74*
24
1,579 73*
1,575 73*
332 23*
957 59*
954 59*
953 55*
1,441 02*
1,535 34*
50
75*
155*
21
45*
30
42
105*
125*
144
114
452*
375*
522
50*
240
245*
459 59*
455 59*
195*
51*
255
27
33
39
625 05*
9
163
1,740 10*
15
36
45
72
324
468
93
453
1,200 10*
80 10*
152 25*
158 25*
176 07*
97 50*
170 62*
54
102
162
78
136 50*
443 62*
633 74*
24
1,579 73*
1,576 73*
332 23*
957 69*
954 69*
963 68*
1,441 02*
1,635 34*
50
76
168
21
48
30
42
108
126
144
114
462
378
522
60
240
246
459 69*
456 69*
198
61
255
22*
33
39
625.05
9
163
1,240.10*
15
36
45
22*
324
468
93
453
1,200.10
80.10
152.25
158.25
126.02*
92.50*
120.62*
54
102
162
28*
136.50
443.62
633.24*
24
1,529.23*
1,526.23*
332.23
952.69*
954.69
963.68
1,441.02
1,635.34
50
26*
168
2 1*
48
30
42
108
126
144
1 14*
462
328*
522
60
240
246
459.69
456.69
198
6 1*
255
27
33
39
625.05
9
163
1,740.10
15
36
45
72
324
468
93
453
1,200.10
80.10
152.25
158.25
176.07
97.50
170.62
54
102
162
78
136.50
443.62
633.74
24
1,579.73
1,576.73
332.23
957.69
954.69
963.68
1,441.02
1,635.34
50
76
168
2 1*
48
30
42
108
126
144
1 14*
462
378
522
60
240
246
459.69
456.69
198
6 1*
255

Оцифровка изображений по одному

Ок, что если требуется оцифровывать изображения одно за другим в режиме реального вренени?

Пробую по одному.
./exp5 - one by one> for /r %i in (*.png) do tesseract "%i" "%i"
Двух и трехзначные числа не определяются вовсе!

625.05
1740.10

Оцифровка небольшими пакетами

А если требуется оцифровывать изображения пакетами по несколько изображений (6 или 10 в пакете)? Пробую по десять.
./exp6 - ten in line> tesseract teninline.png teninline

Распознаются, и даже без пробела в числе 61.

Выводы

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

Предварительная обработка изображения имеет больший эффект, чем обучение. Увеличивайте со сглаживанием: convert -resize…

Распознавание отдельно стоящих «коротких» двух и трехзначных чисел неудовлетворительно - числа надо собирать в пакеты.

Но в целом tesseract почти идеально справился с задачей, несмотря на то, что он заточен под другие задачи - распознавание надписей на фото и видео, сканах документов.

Если есть готовые решения, нет смысла изобретать костыли и велосипеды. С особым цинизмом это утверждение доказали авторы криптолокера, который для своих целей пользовался 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 [email protected]#$%^&(),.{}<>/? - ужасно. Гораздо лучше: в чащах {юга} жил-(был) цитрус, да! но? <фальшивый> $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 по-русски