开源OCR引擎Tesseract

| 振导社会  | 机器学习应用  程序设计 

简介

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

上图的验证码9531,通过以上命令可正确识别。查看目前支持那些语言:

tesseract --list-langs # chi_sim chi_tra eng osd

语言支持文件位于安装目录的tessdata文件夹中,其中的eng.traineddata文件表示支持英文的识别库。更多语言支持可在github下载

识别配置文件位于安装目录的tessdata/configs文件夹中,其中的digits文件配置为只识别数字,相当于识别的白名单,内容为

tessedit_char_whitelist 0123456789-.

识别库对字体的识别能力影响很大,比如点阵字体:

bitmap font

识别的参数如下:

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?”。

获得训练图片的方法主要有两类:

  1. 通过字体文件自动生成训练图片,通常可以同时得到box文件;
  2. 直接收集图片,或者利用先打印后扫描的方式。

自动新方法(3.03版新功能)

该方法通过字体文件,自动获得训练所需的tif/box文件对。

准备一个utf-8文件(training_text.txt),包含符合上述准则的训练文本。获得期望识别字体的truetype/opentype字体文件,利用text2image1命令创建匹配的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图如下:

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文件,通过可视化工具人工合并,可得到正确的字符框。

紧邻字符的处理方式:

  • 当两个字符靠得很近时,可以通过重新制作训练图片使二者分开;
  • 如果两个相邻字符经常一起出现,那么可以直接将两个字符视为一个对象(box文件第一列为两个字符),并且边界框包含这两个字符3

当训练一个新字符集时,一个好的思路是首先在某一种字体上得到box文件,然后继续完成整个训练过程。制作其它字体box文件时,可借助已训练好的识别库,比如上例采用的-l chi_sim参数。这样得到后续的box文件更容易,而且很有可能大部分字符能正确识别。

但是,不存在增量训练方法。每次mfTrainingcnTraining的过程都要用tr文件从头再来,不能直接使用已有的intproto/pffmtable/normproto文件。

优化Tif/Box文件

通过抽取子集或增加不同的字符或形状提升训练数据:

  • 从box文件中过滤掉不需要的字符。
  • 执行tesseract训练(得到tr文件)。
  • 对每种字体,cat(连接)不同语言的tr文件,并加入自定义字体和字符的tr文件。
  • 按照cat(连接)tr文件的顺序和方式,cat(连接)box文件,交付unicharset_extractor使用。
  • 执行之后的训练过程。cntrainingmftraining最多只能采用64个tr文件,必须将不同语言的tr文件按字体连接在一起(每个tr文件的字体要相同)。tr文件中的字符必须和box文件中的字符顺序一致,也就是box的连接顺序要和tr相同。输入cn/mftrainingunicharset_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版的新功能)、mftrainingcntraining聚类得到。

shapeclustering -F font_properties -U unicharset chi_jyq.fangsong_gb2312.exp0.tr chi_jyq.fangsong_gb2312.exp1.tr

shapeclustering通过形状聚类创建主形状表,并将它写入shapetable文件。除了Indic语言,目前不要使用shapeclustering

如果没有执行shapeclusteringmftraining会生成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_tessdatamftraining还会输出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文件,从而提高识别率。

参考资料

    1. OSX系统中,由于pango库的原因,text2image命令会导致段错误,该命令是在Linux中执行的。 

    2. 原文这样描述:you must cat together the tr files for each font into several single-font tr files. 

    3. 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. 

    4. 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. 


    打赏作者


    上一篇:高性能计算概述     下一篇:Single Image Haze Removal Using Dark Channel Prior