iOS中如何用OCR高效識別手機號

背景

最近項目中有個需求,就是讓識別手機號。其實按照產品的思路就是外購,並且確實已經開始採購。因爲採購過程其實也是漫長的,因而乎本人就準備本身研究一下實現手機號識別。linux

若是用一些第三方的話,好比百度OCR識別是有限制的,並且就是集成SDK而已,沒什麼可研究的。最終通過尋尋覓覓,找到了咱們今天的主角--TesseractTesseract是一款由HP實驗室開發由Google維護的開源OCR(Optical Character Recognition , 光學字符識別)引擎。git

引入Tesseract

工程引入過程真可謂是一波三折,在本身工程引入的時候遇到了挺多的問題。github

首先咱們經過Github上的開源代碼下載Tesseract主工程,在主工程中咱們能夠看到Tesseract會被單獨編譯成一個動態庫bash

引入項目

  • 將編譯好的TesseractOCR.framework導入到工程中
  • 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);
複製代碼

其實經過最簡單的三部咱們已經完成了TesseractOCR集成。是否是很簡單啊?其實否則,經過以上簡單三步咱們可能會遇到如下問題。app

問題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文件夾的方式的時候致使的。 優化

1564018584898.jpg
咱們只要在導入的時候注意選擇 Create folder references就能夠了。

一般經過以上步驟,此時個人demo可以正常運行起來了,並且可以識別出原來工程中的圖片ui

高效識別手機號

咱們項目中的需求就是經過視頻流截取一張圖片,而後再經過TesseractOCR識別。效果圖以下:spa

1564019370003.jpg

經過以上代碼集成到咱們本身的工程發現一個問題就是手機號識別率很低。由於咱們用的是eng訓練庫,因此就考慮是否是水土不服,將他換成中文的訓練庫。命令行

說幹就幹咱們就去官方下載最新的4.0.0中文訓練庫chi_sim.traineddata

  • 放到tessdata文件夾中
  • 更改代碼,將eng改爲chi_sim
G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:@"chi_sim"];
複製代碼

本覺得會大功告成,反而這裏就是重頭戲!

問題3

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

問題4

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秒,稍微慢了點,並且那個距離的解決也不是最好的。各位若是有什麼好的解決方案能夠與我聯繫

個人博客

FlyOceanFish

chi_sim最新合成庫

相關文章
相關標籤/搜索