简介
Tesseract是开源的OCR引擎。Tesseract最初设计用于英文识别,经过改进引擎和训练系统,它能够处理其它语言和UTF-8字符。Tesseract 3.0能够处理任何Unicode字符,但并非在所有语言上都工作得很好。Tesseract在庞大字符集语言(比如中文)上较慢,但是工作良好。
Tesseract需要知道相同字符的不同形状,也就是不同字体。最多允许的字体数量在intproto.h
中通过MAX_NUM_CONFIGS
定义,目前支持64种。当训练字体数量超过32种时,速度显著下降。
使用入门
直接输入无参数命令tesseract
可查看其用法:
tesseract
基本使用方法[终端命令]:
tesseract images/9531.jpeg stdout -l eng -psm 7 digits
images/9531.jpeg
:输入待OCR的图片;stdout
:输出结果到终端,也可用文件名,表示输出到文件;-l eng
:使用英文识别库;-psm 7
:表示分页方式,7
表示将图片视为单行文字;digits
:识别配置文件,这里表示只识别数字。
上图的验证码9531,通过以上命令可正确识别。查看目前支持那些语言:
tesseract --list-langs # chi_sim chi_tra eng osd
语言支持文件位于安装目录的tessdata
文件夹中,其中的eng.traineddata
文件表示支持英文的识别库。更多语言支持可在github下载。
识别配置文件位于安装目录的tessdata/configs
文件夹中,其中的digits
文件配置为只识别数字,相当于识别的白名单,内容为
tessedit_char_whitelist 0123456789-.
识别库对字体的识别能力影响很大,比如点阵字体:
识别的参数如下:
tesseract images/bitmap_test.tif stdout -l chi_sim -psm 7
采用google code上老的中文识别库,结果就不太好:
项目名称 = 北京丰台 区花乡四台庄(中失村料技园丰台园东区三期)15 16一2 正地挪
换用github上的3.04版本中文识别库,结果有很大提升:
项目名称 : 北京丰台 区花乡四合庄〔中夫村科技园丰台园东区三期〕1… 16一2 1地块C
通过自己训练识别库,也可得更好的识别结果:
项目名称 : 北京丰台 区花乡四合庄(中关村科技园丰台园京区2期)15 16-2 1地块C
训练识别库
为了训练一种新语言当识别库,需要在tessdata子文件夹中创建一些数据文件,然后用combine_tessdata
将它们合并为一个文件。命名约定(naming convention)是languagecode.file_name
,其中languagecode
按ISO 638-3标准,当然也可使用任何字符串。用于英文识别库(3.00)的文件包括:
- tessdata/eng.config
- tessdata/eng.unicharset
- tessdata/eng.unicharambigs
- tessdata/eng.inttemp
- tessdata/eng.pffmtable
- tessdata/eng.normproto
- tessdata/eng.punc-dawg
- tessdata/eng.word-dawg
- tessdata/eng.number-dawg
- tessdata/eng.freq-dawg
最终合并得到的文件是tessdata/eng.traineddata,tessdata/eng.user-words文件可以单独提供。traineddata文件是输入文件的简单连接,包含已知文件类型的偏移表。通过查看ccutil/tessdatamanager.h
可知目前可接受的文件名。
输入文件(lang.config、lang.unicharambigs、font_properties、box文件、字典的wordlists……)需要满足如下标准:
- 不含BOM的ASCII或UTF-8编码;
- Unix风格的行结束符(‘\n’);
- 最后一个字符必须是行结束符(没有会报错
last_char == '\n':Error:Assert failed...
)。
训练识别库至少需要unicharset、inttemp、normproto和pfftable这几个文件。如果只识别有限的字体(例如一种字体),那么单个训练页可能就够了。
训练步骤如下:
命令/工具 | 输入文件类型 | 输出文件类型 | 备注 |
---|---|---|---|
text2image |
ttf | box、tif | 可选步骤 |
tesseract |
tif | box | |
tesseract |
tif、box | tr | |
unicharset_extractor |
box | unicharset | |
set_unicharset_properties |
unicharset | unicharset | 可选步骤 |
font_properties | 手动步骤 | ||
shapeclustering |
font_properties、unicharset、tr | shapetable | 可选步骤 |
mftraining |
font_properties、unicharset、tr | unicharset、shapetable、inttemp、pffmtable | |
cntraining |
tr | normproto | |
words_list | 手动步骤 | ||
wordlist2dawg |
words_list | DAWG | 可选步骤 |
unicharambigs | 手动步骤 | ||
combine_tessdata |
* | traineddata |
训练流程中有些是手动的(得到font_properties、words_list、unicharambigs文件),用到的相关工具位于training子目录。
生成训练图片
创建训练文件需注意的重要事项:
- 确保每个字符的最少样本数,10个较理想,但对稀有字符5个也可。
- 更频繁的字符应该有更多的样本,最少20个。
- 不要错误地将所有非字符组织在一起。例如:“The quick brown fox jumps over the lazy dog. 0123456789 !@#%^&(),.{}<>/?”就很糟糕,更好的组织是“The (quick) brown {fox} jumps! over the 3,456.78
#90 dog & duck/goose, as 12.5% of E-mail from aspammer@website.com is spam?”。
获得训练图片的方法主要有两类:
- 通过字体文件自动生成训练图片,通常可以同时得到box文件;
- 直接收集图片,或者利用先打印后扫描的方式。
自动新方法(3.03版新功能)
该方法通过字体文件,自动获得训练所需的tif/box文件对。
准备一个utf-8文件(training_text.txt),包含符合上述准则的训练文本。获得期望识别字体的truetype/opentype字体文件,利用text2image
1命令创建匹配的tif/box文件对:
text2image --text=training_text.txt --outputbase=chi_jyq.fangsong_gb2312.exp0 --font='FangSong_GB2312' --fonts_dir=./Fonts
这样就可以得到chi_jyq.fangsong_gb2312.exp0.tif和chi_jyq.fangsong_gb2312.exp0.box两个文件。本例采用的training_text.txt文件内容为:
项目名称:北京丰台区花乡四合庄(中关村科技园丰台园东区三期)1516-21地块C
得到的tif图如下:
得到的box文件前部分片段:
项 57 4617 100 4664 0
目 115 4619 144 4662 0
名 156 4619 194 4667 0
称 206 4621 251 4670 0
: 259 4625 267 4651 0
北 306 4624 351 4671 0
京 358 4623 400 4673 0
丰 409 4624 450 4674 0
台 461 4625 497 4673 0
区 512 4628 550 4673 0
花 556 4627 601 4677 0
乡 612 4628 645 4676 0
辅助软件
text2image自动生成tif/box文件对的局限性在于:
- 只支持truetype/opentype这样的矢量字体,对于bitmap点阵字体无能为力;
- 这是3.03版本才具有的新功能,而且目前在OSX系统无法正常使用。
因此,需要其它的自动化方案。借助可视化软件jTessBoxEditor,可以不受上述约束,利用其“TIFF/Box Generator”模块,自动生成tif/box文件对。
手动老方法
该方法需要首先得到字符图像(比如通过打印扫描方式),获取字符图像需注意:
- 打印的时候,字符要分开。若间隔不够,生成tr文件时会导致错误“FAILURE! box overlaps no blobs or blobs in multiple rows”。
- 训练数据应按字体组织。理想情况下,单个字体的所有样本应组成一个tiff文件。因此,单个字体的全部训练数据可有很多页,这使得能够训练大字符集(large-character-set)语言。
- 不必对多种尺寸训练,10号字体即可(对小字例外:若想识别窄于15像素的字体,应另外训练或识别前放大图像)。
- 不要在同一图像文件中混杂多种字体(单个tr文件应当精确)。混搭会使聚类时特征劣化,导致识别错误。
可以使用多达64个(多页的)训练文件(图片),最好是混合字体斜体和粗体风格(在不同文件中)。64个图像文件是对字体数量的限制。每个字体应当放到单个的多页tiff文件,box文件中每个字符坐标后面的数字确定了页码。因此,对给定字体,能够创建任意大的训练数据,使得能够训练大字符集语言。另一种方法是对单个字体创建多个单页的tiff文件,然后必须对每个字体cat(Linux中的文件连接命令)合并多个tr文件为只含一个字体的单个tr文件2。任何情况下,输入给mftraining的每个tr文件必须是单一字体。
获取Box文件
如果只有字符图片数据,还需要为每张图创建一个box文件。它是一个文本文件,列出了训练图像中的字符,按顺序,一个字符一行,包含字符边界框的坐标。此步骤的关键是手动调整该文件,得到字符正确的坐标。
Tesseract根据tif图生成box文件:
tesseract chi_jyq.fangsong_gb2312.exp0.tif chi_jyq.fangsong_gb2312.exp0 -l chi_sim batch.nochop makebox
得到的box存在错误,如下所示:
需要修改box文件,通过可视化工具人工合并,可得到正确的字符框。
紧邻字符的处理方式:
- 当两个字符靠得很近时,可以通过重新制作训练图片使二者分开;
- 如果两个相邻字符经常一起出现,那么可以直接将两个字符视为一个对象(box文件第一列为两个字符),并且边界框包含这两个字符3。
当训练一个新字符集时,一个好的思路是首先在某一种字体上得到box文件,然后继续完成整个训练过程。制作其它字体box文件时,可借助已训练好的识别库,比如上例采用的-l chi_sim
参数。这样得到后续的box文件更容易,而且很有可能大部分字符能正确识别。
但是,不存在增量训练方法。每次mfTraining
和cnTraining
的过程都要用tr文件从头再来,不能直接使用已有的intproto/pffmtable/normproto文件。
优化Tif/Box文件
通过抽取子集或增加不同的字符或形状提升训练数据:
- 从box文件中过滤掉不需要的字符。
- 执行
tesseract
训练(得到tr文件)。 - 对每种字体,cat(连接)不同语言的tr文件,并加入自定义字体和字符的tr文件。
- 按照cat(连接)tr文件的顺序和方式,cat(连接)box文件,交付
unicharset_extractor
使用。 - 执行之后的训练过程。
cntraining
和mftraining
最多只能采用64个tr文件,必须将不同语言的tr文件按字体连接在一起(每个tr文件的字体要相同)。tr文件中的字符必须和box文件中的字符顺序一致,也就是box的连接顺序要和tr相同。输入cn/mftraining
和unicharset_extractor
命令的tr和box文件顺序必须一致。
Tesseract训练
对每个训练图像和box文件对,在训练模式运行Tesseract:
tesseract chi_jyq.fangsong_gb2312.exp0.tif chi_jyq.fangsong_gb2312.exp0 box.train.stderr
若上述命令最后一个参数为box.train
,出错信息会写入tesseract.log文件而非stderr。该命令输出tr文件,它包含了每个字符的特征,也会输出只包含单个新行的txt文件。
上述命令可能会出错,得到如下输出:
FAIL!
APPLY_BOXES: boxfile line 22/园 ((1108,4637),(1150,4686)): FAILURE! Couldn't find a matching blob
FAIL!
APPLY_BOXES: boxfile line 25/园 ((1258,4641),(1300,4689)): FAILURE! Couldn't find a matching blob
APPLY_BOXES:
Boxes read from boxfile: 40
Boxes failed resegmentation: 2
Found 38 good blobs.
Generated training data for 4 words
Warning in pixReadMemTiff: tiff page 1 not found
意味着“园”字的块没找到,tr文件中就缺失了“园”字的特征。如果出现FATALITIES
错误,必须先修正box文件修订错误才能继续。FATALITY通常意味着没有找到box文件中的任何字体。要么是坐标错误,要么是字符图像出了问题。如果字符没有可供使用的样本,它就不能被识别,那么得到的inttemp文件和unicharset文件就不匹配,Tesseract会退出。
如果tif/box文件对是通过jTessBoxEditor可视化工具得到的,那么生成文件时选定“Anti-Aliasing”可消除上述错误。
tr文件中特征含义如下:
Every character in the box file has a corresponding set of entries in
the .tr file (in order) like this
UnknownFont <utf8 code(s)> 2
mf <number of features>
x y length dir 0 0
... (there are a set of these determined by <number of features>
above)
cn 1
ypos length x2ndmoment y2ndmoment
The mf features are polygon segments of the outline normalized to the
1st and 2nd moments.
x= x position [-0.5.0.5]
y = y position [-0.25, 0.75]
length is the length of the polygon segment [0,1.0]
dir is the direction of the segment [0,1.0]
The cn feature is to correct for the moment normalization to
distinguish position and size (eg c vs C and , vs ')
计算字符集
Tesseract需要知道能够输出的字符。利用unicharset_extractor
工具,可以从box文件得到unicharset文件:
unicharset_extractor chi_jyq.fangsong_gb2312.exp0.box chi_jyq.fangsong_gb2312.exp1.box
Tesseract需要知道字符的属性(property):isalpha、isdigit、isupper还是islower?这些信息必须编码到unicharset数据文件,文件的每行对应一个字符。
v2版的unicharset文件有4个空格分开的字段:
'character' 'properties' 'script' 'id'
形如:
; 10 Common 46
b 3 Latin 59
W 5 Latin 40
7 8 Common 66
= 0 Common 93
v3.03版的unicharset文件包含了更多的信息:
'character' 'properties' 'glyph_metrics' 'script' 'other_case' 'direction' 'mirror' 'normed_form'
形如:
110
NULL 0 NULL 0
N 5 59,68,216,255,87,236,0,27,104,227 Latin 11 0 1 N
Y 5 59,68,216,255,91,205,0,47,91,223 Latin 33 0 2 Y
1 8 59,69,203,255,45,128,0,66,74,173 Common 3 2 3 1
9 8 18,66,203,255,89,156,0,39,104,173 Common 4 2 4 9
a 3 58,65,186,198,85,164,0,26,97,185 Latin 56 0 5 a
set_unicharset_properties
3.03版本中的新工具可以得到字符集的额外属性:
set_unicharset_properties -U unicharset -O output_unicharset --script_dir=training/langdata
font_properties
3.01版新的要求是font_properties文件。该文件的作用是当字体被识别时,提供字体风格(style)信息。font_properties文件是文本文件,通过-F filename
参数输入给命令mftraining
。
font_properties文件的每行格式如下:
<fontname> <italic> <bold> <fixed> <serif> <fraktur>
<fontname>
表示字体名,不允许有空格,其它几个取值为0或1,表示该字体是否具有这个属性。
当运行mftraining
时,每个tr文件名必须匹配font_properties文件中的一条,否者mftraining
会退出。tr文件命名应当是fontname.tr或[lang].[fontname].exp[num].tr。
一个font_properties文件示例:
fangsong_gb2312 0 0 0 0 0
聚类
当抽取了所有训练数据的字符特征后,需要通过聚类创建原型(prototype)。字符的形状特征可通过shapeclustering
(3.02版的新功能)、mftraining
和cntraining
聚类得到。
shapeclustering -F font_properties -U unicharset chi_jyq.fangsong_gb2312.exp0.tr chi_jyq.fangsong_gb2312.exp1.tr
shapeclustering
通过形状聚类创建主形状表,并将它写入shapetable文件。除了Indic语言,目前不要使用shapeclustering
。
如果没有执行shapeclustering
,mftraining
会生成shapetable:
mftraining -F font_properties -U unicharset -O chi_jyq.unicharset chi_jyq.fangsong_gb2312.exp0.tr chi_jyq.fangsong_gb2312.exp1.tr
chi_jyq.unicharset
是输出的unicharset,将会用于combine_tessdata
。mftraining
还会输出inttemp(形状原型)和pffmtable(每个字符的期望特征数)两个文件。该程序也会输出Microfeat,但是这里不会用到。
traineddata文件中必须包含shapetable。
cntraining
将会得到normproto(规范化的敏感原型)文件:
cntraining chi_jyq.fangsong_gb2312.exp0.tr chi_jyq.fangsong_gb2312.exp1.tr
字典数据(可选项)
Tesseract对每种语言使用了多达8个字典文件。这些文件都是可选项,用于辅助确定不同可能字符组合的可能性。 其中7个文件为有向无环字图(DAWG,directed acyclic word graph)格式,另外一个是纯UTF-8文本。
为了得到DAWG字典文件,首先需要语言的单词列表(wordlist)。可以用合适的字典文件(比如来自拼写检查器ispell、aspell和hunspell等)作为wordlist的基础。wordlist是UTF-8文本,一行一个单词。将wordlist分割成不同的集合,比如:频繁单词,以及除此之外的单词。然后使用[wordlist2dawg](https://github.com/tesseract-ocr/tesseract/blob/master/doc/wordlist2dawg.1.asc)
得到DAWG文件:
wordlist2dawg frequent_words_list lang.freq-dawg chi_jyq.unicharset
wordlist2dawg words_list lang.word-dawg chi_jyq.unicharset
若需要字典的wordlist示例,可以用combine_tessdata
解开已有的traineddata文件,然后用dawg2wordlist
提取wordlist文件:
combine_tessdata -u chi_sim.traineddata chi_sim
dawg2wordlist chi_sim.unicharset chi_sim.freq-dawg wordlist
最后的unicharambigs文件
unicharambigs描述了字符之间存在的混淆,该文件可手动填写,一个例子如下:
v1
2 ' ' 1 " 1
1 m 2 r n 0
3 i i i 1 m 0
第1行表示版本,剩下的行是由tab分割的字段,遵循如下格式:
<number of characters for match source> <tab> <characters for match source> <tab> <number of characters for match target> <tab> <characters for match target> <tab> <type indicator>
<type indicator>
取值为1或0。1表示强制替换,0表示非强制替换。上例中,凡是' '
都用"
替换。非强制替换的含义:若用target
替换source
能得从非字典单词创建字典单词,则进行替换。那些利用混淆规则能转换成另一个字典单词的字典单词,不会用于训练自适应分类器。
v2版的unicharambigs文件更为简单4,字段间用空格分开:
v2
'' " 1
m rn 0
iii m 0
和其它大多数文件一样,unicharambigs必须为UTF-8编码,并以换行符作为文件的结束。该文件不是必须的。
全部组合起来
将生成的所有文件(shapetable、normproto、inttemp、pffmtable等)加上lang.
前缀,lang通常是3个字符的语言码,然后执行如下合并:
combine_tessdata lang.
可得识别库文件lang.traineddata,最后就可以进行OCR:
tesseract image.tif output -l lang
Python接口
from pyocr import tesseract
builder = tesseract.builders.TextBuilder()
builder.tesseract_configs = ['-psm', '7', 'scbid']
result = tesseract.image_to_string(Image.open('ocr_test.png'), 'eng', builder)
性能提升
直接修改traineddata文件
针对具体问题,可用combine_tessdata
解开traineddata库文件,修改DAWG和unicharambigs文件,然后再生成traineddata文件,从而提高识别率。
参考资料
- An Overview of the Tesseract OCR Engine
- Tesseract Open Source OCR Engine (main repository)
- TrainingTesseract
- 在ubuntu下使用 tesseract-ocr 文字识别工具(基础篇)
-
OSX系统中,由于pango库的原因,
text2image
命令会导致段错误,该命令是在Linux中执行的。 ↩ -
原文这样描述:you must cat together the tr files for each font into several single-font tr files. ↩
-
As of 3.00, there is a limit of 24 bytes for the description of a “character”. This will allow you between 6 and 24 unicodes to describe the character, depending on where your codes sit in the unicode set. If anyone hits this limit, please file an issue describing your situation. ↩
-
Note the downside of this simpler format is that Tesseract has to encode the utf-8 strings into the components of the unicharset. In complex scripts, this encoding may be ambiguous. In this case, the encoding is chosen such as to use the least utf-8 characters for each component, ie the shortest unicharset components will make up the encoding. ↩