背景
最近項目中有個需求,就是讓識別手機號江醇。其實按照產(chǎn)品的思路就是外購濒憋,而且確實已經(jīng)開始采購。由于采購過程其實也是漫長的陶夜,于是乎本人就準(zhǔn)備自己研究一下實現(xiàn)手機號識別凛驮。
如果用一些第三方的話,比如百度OCR識別是有限制的条辟,而且就是集成SDK而已黔夭,沒什么可研究的宏胯。最終經(jīng)過尋尋覓覓,找到了我們今天的主角--Tesseract本姥。Tesseract
是一款由HP實驗室開發(fā)由Google維護(hù)的開源OCR(Optical Character Recognition , 光學(xué)字符識別)引擎胳嘲。
引入Tesseract
工程引入過程真可謂是一波三折,在自己工程引入的時候遇到了挺多的問題扣草。
首先我們通過Github上的開源代碼下載Tesseract
主工程了牛,在主工程中我們可以看到Tesseract
會被單獨編譯成一個動態(tài)庫
引入項目
- 將編譯好的
TesseractOCR.framework
導(dǎo)入到工程中 - 將
tessdata
文件夾拖到自己的工程中 - 測試demo
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);
其實通過最簡單的三部我們已經(jīng)完成了TesseractOCR
集成。是不是很簡單俺矫睢鹰祸?其實不然,通過以上簡單三步我們可能會遇到以下問題密浑。
問題1
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
即可解決
問題2
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
文件夾的方式的時候?qū)е碌摹?br>
我們只要在導(dǎo)入的時候注意選擇
Create folder references
就可以了蛙婴。
通常通過以上步驟,此時我的demo能夠正常運行起來了尔破,而且能夠識別出原來工程中的圖片
高效識別手機號
我們項目中的需求就是通過視頻流截取一張圖片街图,然后再通過TesseractOCR
識別。效果圖如下:
通過以上代碼集成到我們自己的工程發(fā)現(xiàn)一個問題就是手機號識別率很低懒构。因為我們用的是eng
訓(xùn)練庫餐济,所以就考慮是不是水土不服,將他換成中文的訓(xùn)練庫胆剧。
說干就干我們就去官方下載最新的4.0.0中文訓(xùn)練庫chi_sim.traineddata
絮姆。
- 放到
tessdata
文件夾中 - 更改代碼,將
eng
改成chi_sim
G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:@"chi_sim"];
本以為會大功告成,反而這里就是重頭戲!
問題3
allow_blob_division
在chi_sim.traineddata文件目錄下,使用命令行執(zhí)行:
combine_tessdata -e chi_sim.traineddata chi_sim.config
執(zhí)行完后秩霍,在目錄下出現(xiàn)chi_sim.config的文件篙悯,打開該文件;
在allow_blob_division F這一行的前面加#铃绒,注釋掉
即:# allow_blob_division F
然后鸽照,在執(zhí)行命令行:
combine_tessdata -o chi_sim.traineddata chi_sim.config
到此在使用 chi_sim.traineddata文件就不會報read_params_file: parameter not found: allow_blob_division
問題4
actual_tessdata_num_entries_ <= TESSDATA_NUM_ENTRIES:Error:Assert failed:in file ../../ccutil/tessdatamanager.cpp, line 53
這個問題我集合Google和Github上的Issues得出統(tǒng)一結(jié)論:chi_sim.traineddata
版本庫不對應(yīng),因為我們下載的是4.0.0最新版颠悬,所以按照結(jié)論我們就換成一個較低的版本矮燎,而且確實可以啦!
不過綜合對比下來感覺識別率還不是很好椿疗,畢竟最新的訓(xùn)練庫代表著識別率最高漏峰,所以心里隱隱還是不甘心糠悼。
通過問題3不知大家有沒有感覺到chi_sim.traineddata
可以進(jìn)行分解届榄,然后再次合成呢?
通過結(jié)合combine_tessdata有關(guān)介紹此命令的文章倔喂,我有了一個大膽的想法铝条,將老版本和新版本的的chi_sim.traineddata
分別解包靖苇。然后將兩個集合起來重新合成。
我們通過以下兩行即可實現(xiàn)
合成
combine_tessdata -o chi_sim.traineddata chi_sim.
解壓
combine_tessdata -e chi_sim.traineddata chi_sim.
- 解壓班缰。首先我們通過命令分別解壓最新版和舊版的
chi_sim.traineddata
通過解壓出來的文件贤壁,我們對比發(fā)現(xiàn)其實新版比舊版少了幾個文件。這時候我有個更大膽的想法埠忘,我只要我需求的文件脾拆,我只要數(shù)字識別庫就好了,通過這種方式可以極大的減少包的大小莹妒,不過通過嘗試以失敗告終名船。因為只要我們需要的庫的話,數(shù)量與代碼中的數(shù)量又不匹配了
- 替換旨怠。將新版包里的文件全部復(fù)制到舊版中進(jìn)行替換
- 合成渠驼。通過合成命名合成一個新的
chi_sim.traineddata
將我們合成的chi_sim.traineddata
放到工程中就不會再報問題4了。而且識別率很高鉴腻。(我自己合成的已經(jīng)分享出來了在文章末尾)
優(yōu)化識別率
結(jié)合上步合成的最新訓(xùn)練庫迷扇,通過多次嘗試,以下代碼是識別率最高的了爽哎。
G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:@"chi_sim"];
tesseract.engineMode = G8OCREngineModeTesseractOnly;//必須要設(shè)置此模式
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];
是不斷的使用中蜓席,發(fā)現(xiàn)一個問題,用戶手機與紙的距離是個問題课锌,如果用戶離著太遠(yuǎn)識別率非常低瓮床,只有在一個適當(dāng)?shù)木嚯x能基本很快就能識別出來,而且正確率非常高产镐。
我的解決方案就是通過在掃描界面上增加一個框隘庄,這里能夠有效控制用戶的距離
總結(jié)
最終實現(xiàn)了手機號的識別,不過這個識別速度要2到3秒癣亚,稍微慢了點丑掺,而且那個距離的解決也不是最好的。各位如果有什么好的解決方案可以與我聯(lián)系