识别率低是因为tesseract 想做到适应各种字体、各种分辨率,结果就造成了识别率低的尴尬局面。
要想识别率高的话,可以采用abbyy finereader是ocr(光学辨识)软件。比较常用的功能为:扫描到 Word、将PDF图像、图片转换为 Word 文档或者可编辑可搜索的PDF文档,另外也支持将PDF图像转换为 Excel 文档。
OCR 识别是肯定会存在错误的,所以识别转换完成以后记得要和原文核对。 设置语言种类的话,越少识别率越高,就是说如果文件只有中文的话,那么就设置中文一种语言,不要选择其他语言,这样识别速度也会提高。
之前使用 sudo apt-get install tesseract-ocr 安装的tesseract-ocr有问题,不能使用psm参数。决定手动编译安装。下面参考别人的安装过程。
安装所需的库
sudo apt-get install libpng12-dev。
sudo apt-get install libjpeg62-dev。
sudo apt-get install libtiff4-dev。
sudo apt-get install gcc。
sudo apt-get install g++。
sudo apt-get install automake。
pytesser 调用了 tesseract,因此需要安装 tesseract,安装 tesseract 需要安装 leptonica,否则编译tesseract 的时候出现 "configure: error: leptonica not found"。
以下都是解压编译安装的老步骤:
./configure
make -j4
sudo make install。
下载安装leptonica
http://www.leptonica.org/download.html 或者。
http://code.google.com/p/leptonica/downloads/list。
最新的是leptonica-1.69.tar.bz2。
下载安装tesseract
http://code.google.com/p/tesseract-ocr/。
最新的是 tesseract-ocr-3.02.02.tar.gz。
识别多种字体、多种语言的字符,在实际应用中是很常见的问题。
经过测试,及查看tesseract3.01的源码,tesseract 3.01版本是不支持多语言、多种字体OCR识别的。
tesseract3.01版本不支持新训练的数据,加入原有字符集,并不支持多个训练库的联合使用方式。
如何利用tesseract进行多语言或多字体识别哪?
一种方法是自己训练字符集,将所有的字体、语言的训练数据放入一个训练数据文件内。这种方法需要庞大的训练样本数据,工作量大,而且舍弃原有的google的训练库,实在是太可惜了。
另外一种方法就是升级tesseract到3.02版本。目前3.02版本还没有release,需要自行下载源码,编译,生成。tesseract3.02支持多个训练库联合使用的方式,这样就能支持多语言、多字体识别,并且tesseract3.02版本的固有数据集应该增加了大量的样本,因为其体积比3.01版本的数据文件大了很多。
tesseract多语言识别的原理及算法在文章Adapting the Tesseract Open Source OCR Engine for Multilingual OCR有专门的介绍。这里记录下自己对这篇文章的理解。
OCR字符识别的热点趋势:
拉丁文-> 中文、日文、韩文 -> 阿拉伯文 -> 印度语。
这几种语言字符有各自的特征。
汉字、日文:有一些相同文字,但文字有上千种形状结构。
韩文:自己特有的文字结构,而且数量更多。
阿拉伯文:字母都连起来书写,且字母处在不同的位置,其形状也不同。
印度文:将字符连起来形成上千种形状,来表示不同的音节。其包含了阿拉伯文和韩文面临的问题。
汉字、韩文和印度文都有部首和词根的结构。相比韩文,汉字的词根在不同的字里,其形状也是不固定的,且常和其他部首连写。而印度文更复杂些。
拉丁文字符识别在另外一篇文章中有介绍,这里写些思路与未提到的问题。
1. 在连通区域分析后,找出blob,即单个字母块。
2. 行检测。利用等间距检测与分割算法,包括识别词与字母的空白区别。
3. 单个字符识别,并对初次识别效果不佳的字符进行分割与联想,对于多种可能,就应用词典的距离计算,选择出最好的可能性。
4. 多次识别:识别效果好的字符作为训练样本,对其他不好的字符进行再次识别。(自适应分类器)
问题:
一般一个字母是单连通区域,但也有例外,一个字母有多个连通区域,或嵌套孔洞,如圆圈中有一个c或R的字符。
--------------
文章的排版:
1. 横排、竖排、混合排列
tesseract最初支持处理横排的情况,若处理各种排列,tesseract需要考虑更多的特征检测。
段落缩进的检测; 字符间距检测(竖排字符的间距中值小于字符大小的均值);文本行(列)检测。
另外,对于竖排占多数的页面,可以旋转90度,这样大部分文本可转换为横排,减少竖排区域误检率。
混合排列在各种文字中都存在且常见,所以,tesseract要处理这些情况。
2. 文本行、列检测
行检测算法:
每行文本中的字符直接的间距比较小,一般比行间距小,且一般字符大小都差不多,除了个别特殊位置上的字符。利用这个特征,将邻近字符串起来,就形成了一条线。多条线形成后,就有了多条线平行的特征,多条平行线就形成了一个模块。
不同的平行线形成的排版,就能将整个页面分割开来。
行检测完成后,就能检测行内的单个字符了。对于拉丁字符,空格是最小识别单位的特征,而一些语言的空格特征不明显,如中文字符,字、词之间空格没差别,词根之间也有空格,将一个连通区域作为一个独立的识别单位,这种识别方法缺少整体的识别能力,如字典等。一种解决方法是,先识别标点符号(punctuations),但对长句子,还是有局限性。
若存在多种语言混合编排的情况,字符的大小特征可能不一样,如拉丁与汉字。这就需要不同的语言字符,应用不同的阈值进行过滤。
3. 古斯拉夫语Cyrillic,类似俄语之类吧,小写字母x字符高度的估计。
拉丁字符检测的方法,不适用于这种语言。
俄语的检测需要应用其他的特征。这里对俄语不熟悉,就忽略不看了。
4. 字、词的识别
包括分割、搜索及形状分类
字母语言的识别,与象形文字的识别,有很多不同。象形文字的词汇的边界不如字母文字清晰。
对于象形文字间的关联,tesseract应用最优优先搜索方法(best-first-search),在词典中寻找匹配的词汇,这个比字母词汇搜索需要更深的搜索层次。
形状分类
线宽、线长都可以作为字符的形状特征。对于一个字或字符,可以先粗略的分类,多选几个近似的分类,然后,再仔细的分类,从候选的类别选出可能的类别。
6. 上下文关联后处理
字典搜索
android调用tesseract实现OCR功能的方法为:
一、下载&编译
1、首先下载tess-two
git clone git://github.com/rmtheis/tess-two tess。
2、进入 tess目录,里面有三个项目,只需要进入tess-two就可以直接编译了。
cd tess/tess-two。
ndk-build
3、编译好后,将src下的两个包以及libs导入到自己的项目就可以用。
二、使用
tesseract 使用了 leptonica的图像处理库,对于图像处理还是比较强大的。
Android官方地址:tesseract-android-tools。
但它必须要一个匹配库,即tessdata,我们可以从官方拷贝,在前面git的项目里面tesseract源码目录有现成的tessdata可以用,对于中文,google code上也有下载,当然也可以自己训练不同语言的tessdata。
包leptonica的类我们不必使用,只要使用tess包的类就行了。
TessBaseAPI
使用时,首先创建TessBaseAPI对象。
代码为:
TessBaseAPI baseApi=new TessBaseAPI();。
//初始化tess
//android下面,tessdata肯定得放到sd卡里了。
//如果tessdata这个目录放在sd卡的根目录。
//那么path直接传入sd卡的目录。
//eng就是英文,关于语言,按ISO 639-3标准的代码就行,具体请移步wiki。
baseApi.init("tessdata文件夹的父级目录", "eng");。
//options是为了缩放图片,这个酌情缩放,图片小的话可以不缩放。
BitmapFactory.Options options=new BitmapFactory.Options();。
//缩小为原来的1/2
options.inSampleSize=2;。
//bitmap,我这里是以流的形式,只要能形成Bitmap就行。
Bitmap bitmap = BitmapFactory.decodeStream(instream,null,options); 。
instream.close(); 。
//如果图片有Alpha值,那么最好设置一下。
/*ExifInterface exif = new ExifInterface(filename)。
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); 。
int rotate = 0;。
switch (exifOrientation) {。
case ExifInterface.ORIENTATION_ROTATE_90:。
rotate = 90;。
break;。
case ExifInterface.ORIENTATION_ROTATE_180:。
rotate = 180;。
break;。
case ExifInterface.ORIENTATION_ROTATE_270:。
rotate = 270;。
break;。
}
if (rotate != 0) { 。
// Getting width & height of the given image.。
int w = bitmap.getWidth();。
int h = bitmap.getHeight(); 。
// Setting pre rotate。
Matrix mtx = new Matrix();。
mtx.preRotate(rotate); 。
// Rotating Bitmap。
bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);。
// tesseract req. ARGB_8888。
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);。
} */
//设置要ocr的图片bitmap。
baseApi.setImage(bitmap);。
//根据Init的语言,获得ocr后的字符串。
String text= baseApi.getUTF8Text();。
//释放bitmap
baseApi.clear();。
//如果连续ocr多张图片,这个end可以不调用,但每次ocr之后,必须调用clear来对bitmap进行释放。
//释放native内存
baseApi.end();
///////////////////////////其它方法//////////////////////////////////。
//获取字符边框
Pixa pixa= baseApi.getCharacters();。
//同上,这个是整段文字的边框。
baseApi.getRegions();。
//同上,只不过这里是条线。
baseApi.getTextlines();。
//剩下的自己测试吧。
//转为rect数组 ,之后,可以很方便的在图片上框出方框。
//怎么框由你。
ArrayList<Rect> rects=pixa.getBoxRects();。
首先做一下背景介绍,Tesseract是一个开源的OCR组件,主要针对的是打印体的文字识别,对手写的文字识别能力较差,支持多国语言(中文、英文、日文、韩文等)。是开源世界里最强的一款OCR组件。当然和世界最强的OCR工具Abbyy相比还是有一点差距,尤其在图片质量较差时,差距还是明显的。
网上有很多关于如何使用这个组件的介绍,不过都是针对英文识别的。而如果是对中文或日文等方块字进行识别,除了需要使用不同的语言包外,还要对Tesseract做一些特别的设置,否则识别率会很低,以下我就和大家分享一下我使用Tesseract对日文做OCR的一些经验。
第一步,是要下载Tesseract组件,最简单的方法就是使用VisualStudio的NUGet来下载。选择第一个组件。
第二步,下载日文语言包,由于在大陆地区无法访问google,所以不能打开官网直接下载语言包。我给出文件的地址,可以使用迅雷下载。
http://tesseract-ocr.googlecode.com/files/tesseract-ocr-3.02.jpn.tar.gz。
下载完成后将语言包文件解压后放到tessdata文件夹下。
到目前为止,准备工作已经就绪,可以开始编写代码。
第三步,初始化Tesseract组件,代码如下。
TesseractEngine engine = new TesseractEngine(@"tessdata文件夹路径", "jpn", EngineMode.Default))。
第四步,设置OCR参数,关于各参数的解释,可以参照官网。
Useful parameters for Japanese and Chinese。
Some Japanese tesseract user found these parameters helpful for increasing tesseract-ocr (3.02) accuracy for Japanese :。
Name Suggested value Description 。
chop_enable T Chop enable. 。
use_new_state_cost F Use new state cost heuristics for segmentation state evaluation 。
segment_segcost_rating F Incorporate segmentation cost in word rating? 。
enable_new_segsearch 0 Enable new segmentation search path. It could solve the problem of dividing one character to two characters 。
language_model_ngram_on 0 Turn on/off the use of character ngram model. 。
textord_force_make_prop_words F Force proportional word segmentation on all rows. 。
edges_max_children_per_outline 40 Max number of children inside a character outline. Increase this value if some of KANJI characters are not recognized (rejected). 。
以下是代码
engine.SetVariable("chop_enable ", "F");。
engine.SetVariable("enable_new_segsearch", 0);。
engine.SetVariable("use_new_state_cost ", "F");。
engine.SetVariable("segment_segcost_rating", "F");。
engine.SetVariable("language_model_ngram_on", 0);。
engine.SetVariable("textord_force_make_prop_words", "F");。
engine.SetVariable("edges_max_children_per_outline", 50);。
这里面chop_enable参数与官网推荐的不太一样,我发现按照官网的设置,会有很多文字识别不出来。
第五步,开始识别。
var page = engine.Process(p);。
var testText = page.GetText();。
var c=page.GetMeanConfidence();。
第一行代码返回一个Page对象,通过该对象可以获得识别的文本,而且还可以获得识别文本所在位置(这个在识别非固定模式文档时非常有用,可以根据关键字动态查找识别字段位置)。
在例子中OCR做全文识别,但是做全文识别很多情况下识别质量一般,最好增加识别区域参数,同时将PageSegMode参数设置为PageSegMode.SingleBlock(代表多行大小相同的文字)或PageSegMode.SingleRow(代表单行大小相同的文字)。
第二行和第三行分别返回识别的文本与识别的信任度。在实际使用时我发现识别信任度不是特别有用。无论识别对错,信任度基本在0.7左右,有些时候信任度较高,识别结果反而是错误的。
经过以上几步,就可以完成日文的OCR。但要让以上代码成功运行,还必须要在安装VC++运行时2012,否则会报错。
我使用以上方法对扫描图片进行测试,发现识别精确度还是比较高的,尤其在指定区域与PageSegMode参数后。但是日文字库也存在一些低级失误,如将数字“1”识别成了汉字“一”等。如果要想解决这个问题,必须要从头训练日文,这个工作量非常大!而这真的是Tesseract一个非常不智能的地方,应该支持在原有训练字库的基础上追加训练内容!或者在官网上提供Box文件和训练用Tif供开发者下载。