最近项目中有个需求,就是让识别手机号。其实按照产品的思路就是外购,并且确实已经开始采购。因为采购过程其实也是漫长的,因而乎本人就准备本身研究一下实现手机号识别。linux
若是用一些第三方的话,好比百度OCR识别是有限制的,并且就是集成SDK而已,没什么可研究的。最终通过寻寻觅觅,找到了咱们今天的主角--Tesseract。Tesseract
是一款由HP实验室开发由Google维护的开源OCR(Optical Character Recognition , 光学字符识别)引擎。git
Tesseract
工程引入过程真可谓是一波三折,在本身工程引入的时候遇到了挺多的问题。github
首先咱们经过Github上的开源代码下载Tesseract
主工程,在主工程中咱们能够看到Tesseract
会被单独编译成一个动态库bash
TesseractOCR.framework
导入到工程中tessdata
文件夹拖到本身的工程中G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:@"eng"];
tesseract.engineMode = G8OCREngineModeTesseractOnly;
tesseract.pageSegmentationMode = G8PageSegmentationModeAutoOSD;
tesseract.image = [UIImage imageNamed:@"image_sample.jpg"];;
[tesseract recognize];
NSString *recognizedText = tesseract.recognizedText;
NSLog(@"%@",recognizedText);
复制代码
其实经过最简单的三部咱们已经完成了TesseractOCR
集成。是否是很简单啊?其实否则,经过以上简单三步咱们可能会遇到如下问题。app
dyld: Library not loaded: @rpath/TesseractOCR.framework/TesseractOCR
Referenced from: /var/containers/Bundle/Application/.../testocr.app/testocr
Reason: image not found
复制代码
这个问题解决方案就是在Xcode->General->Embedded Binaries 点击+,选择TesseractOCR.framework
便可解决测试
Error opening data file /var/containers/Bundle/Application/.../testocr.app/tessdata/chi_sim.traineddata
Please make sure the TESSDATA_PREFIX environment variable is set to the parent directory of your "tessdata" directory.
复制代码
这个问题就是我在在引入tessdata
文件夹的方式的时候致使的。 优化
Create folder references
就能够了。
一般经过以上步骤,此时个人demo可以正常运行起来了,并且可以识别出原来工程中的图片ui
咱们项目中的需求就是经过视频流截取一张图片,而后再经过TesseractOCR
识别。效果图以下:spa
经过以上代码集成到咱们本身的工程发现一个问题就是手机号识别率很低。由于咱们用的是eng
训练库,因此就考虑是否是水土不服,将他换成中文的训练库。命令行
说干就干咱们就去官方下载最新的4.0.0中文训练库chi_sim.traineddata
。
tessdata
文件夹中eng
改为chi_sim
G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:@"chi_sim"];
复制代码
本觉得会大功告成,反而这里就是重头戏!
allow_blob_division
复制代码
在chi_sim.traineddata文件目录下,使用命令行执行:
combine_tessdata -e chi_sim.traineddata chi_sim.config
复制代码
执行完后,在目录下出现chi_sim.config的文件,打开该文件; 在allow_blob_division F这一行的前面加#,注释掉
即:# allow_blob_division F
复制代码
而后,在执行命令行: combine_tessdata -o chi_sim.traineddata chi_sim.config
到此在使用 chi_sim.traineddata文件就不会报read_params_file: parameter not found: allow_blob_division
actual_tessdata_num_entries_ <= TESSDATA_NUM_ENTRIES:Error:Assert failed:in file ../../ccutil/tessdatamanager.cpp, line 53
复制代码
这个问题我集合Google和Github上的Issues得出统一结论:chi_sim.traineddata
版本库不对应,由于咱们下载的是4.0.0最新版,因此按照结论咱们就换成一个较低的版本,并且确实能够啦!
不过综合对比下来感受识别率还不是很好,毕竟最新的训练库表明着识别率最高,因此内心隐隐仍是不甘心。
经过问题3不知你们有没有感受到chi_sim.traineddata
能够进行分解,而后再次合成呢?
经过结合combine_tessdata有关介绍此命令的文章,我有了一个大胆的想法,将老版本和新版本的的chi_sim.traineddata
分别解包。而后将两个集合起来从新合成。
咱们经过如下两行便可实现
合成
combine_tessdata -o chi_sim.traineddata chi_sim.
复制代码
解压
combine_tessdata -e chi_sim.traineddata chi_sim.
复制代码
chi_sim.traineddata
经过解压出来的文件,咱们对比发现其实新版比旧版少了几个文件。这时候我有个更大胆的想法,我只要我需求的文件,我只要数字识别库就行了,经过这种方式能够极大的减小包的大小,不过经过尝试以失败了结。由于只要咱们须要的库的话,数量与代码中的数量又不匹配了
chi_sim.traineddata
将咱们合成的chi_sim.traineddata
放到工程中就不会再报问题4了。并且识别率很高。(我本身合成的已经分享出来了在文章末尾)
结合上步合成的最新训练库,经过屡次尝试,如下代码是识别率最高的了。
G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:@"chi_sim"];
tesseract.engineMode = G8OCREngineModeTesseractOnly;//必需要设置此模式
tesseract.pageSegmentationMode = G8PageSegmentationModeSparseText;//此模式识别率最高
tesseract.charWhitelist = @"0123456789";//白名单
tesseract.charBlacklist = @"abcdefghigklmnopqrstuvwxyz-_";//黑名单
tesseract.image = newImage;
tesseract.rect = CGRectMake((KSCREEN_WIDTH-210-16)/2, 62-2, 210, 20+4);
tesseract.maximumRecognitionTime = 5;
[tesseract recognize];
复制代码
是不断的使用中,发现一个问题,用户手机与纸的距离是个问题,若是用户离着太远识别率很是低,只有在一个适当的距离能基本很快就能识别出来,并且正确率很是高。
个人解决方案就是经过在扫描界面上增长一个框,这里可以有效控制用户的距离
最终实现了手机号的识别,不过这个识别速度要2到3秒,稍微慢了点,并且那个距离的解决也不是最好的。各位若是有什么好的解决方案能够与我联系