本文已授權微信公衆號:鴻洋(hongyangAndroid)原創首發。
公司業務需求,需要做手機號碼的識別。所以有了此篇文章,現在就將實現過程分享給大家。
1.準備工作
首先實現識別數字等字符,我們要知道需要採用OCR (Optical Character Recognition,光學字符識別)來實現。而tesseract是非常不錯的開源OCR工具,但是要在Android中直接使用可能要費點功夫。不過不用擔心,tess-two拯救了我們。
其次是掃一掃識別,那麼很快聯想到的就是常見的二維碼掃描這類的項目。通過掃一掃實時拿到圖像,來做識別。
接下來在Github上找到了QrCodeScanner項目,作者通過一定的優化,使得識別的效率有所提升。那麼我們用它來掃描數字,也會有效率上的提升。
2.實現細節
1.首先是tess-two
的用法。
app下的build.gradle
的配置如下
android {
defaultConfig {
....
ndk {
abiFilters 'armeabi' //自行選擇添加
}
}
}
dependencies {
compile 'com.rmtheis:tess-two:8.0.0'
}
識別方法:
public String detectText(Bitmap bitmap) {
TessBaseAPI tessBaseAPI = new TessBaseAPI();
String path = ""; //訓練數據路徑
tessBaseAPI.setDebug(true);
tessBaseAPI.init(path, "eng"); //eng爲識別語言
tessBaseAPI.setVariable(TessBaseAPI.VAR_CHAR_WHITELIST, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); // 識別白名單
tessBaseAPI.setVariable(TessBaseAPI.VAR_CHAR_BLACKLIST, "!@#$%^&*()_+=-[]}{;:'\"\\|~`,./<>?"); // 識別黑名單
tessBaseAPI.setPageSegMode(TessBaseAPI.PageSegMode.PSM_AUTO_OSD);//設置識別模式
tessBaseAPI.setImage(bitmap); //設置需要識別圖片的bitmap
String inspection = tessBaseAPI.getHOCRText(0);
tessBaseAPI.end();
return inspection ;
}
訓練數據可以在tessdata下載,裏面包含各種語言。當然你自己也可以訓練它,有興趣的可以學習一下相關內容。
2.從tess-two
的用法可以知道,我們最終需要的是識別圖片的Bitmap
。在掃碼項目中我們找到在DecodeHandler
類的decode
方法中,我們會得到一個PlanarYUVLuminanceSource
類的實例。在使用HybridBinarizer
算法解析數據源,最終採用MultiFormatReader
解析圖像出結果。代碼大致如下:
Result rawResult = null;
MultiFormatReader mMultiFormatReade = new MultiFormatReader();
try {
PlanarYUVLuminanceSource source =
new PlanarYUVLuminanceSource(```, false);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
rawResult = mMultiFormatReader.decode(bitmap, mHints);
} catch (ReaderException ignored) {
} finally {
mMultiFormatReader.reset();
}
看完後懵逼了,沒有Bitmap
。經過一番查找,找到了在舊版的zxing中PlanarYUVLuminanceSource
類有renderCroppedGreyscaleBitmap
方法,不知爲何去除了。。。
3.之後修改了一些相機的參數信息,適配了部分設備的預覽效果。基本的頁面修改了一下。這裏就不贅述了。
走一波,如下效果:
可以發現除了數字以外,它將中文識別爲了字母。其實問題首先是我們使用了英文的訓練數據,同時白名單設置了a~z的字母。當然你也不能將字母設置爲黑名單,那樣只會讓識別不出的字符識別爲亂七八糟的數字。
這裏我給出的建議是利用正則去篩選,這樣你可以識別你想要的各種格式數據。我這裏只是做了手機號的簡單識別,大家可以舉一反三去處理。
public static String getTelNum(String sParam){
if(TextUtils.isEmpty(sParam)){
return "";
}
Pattern pattern = Pattern.compile("(1|861)(3|5|7|8)\\d{9}$*");
Matcher matcher = pattern.matcher(sParam);
StringBuilder bf = new StringBuilder();
while (matcher.find()) {
bf.append(matcher.group()).append(",");
}
int len = bf.length();
if (len > 0) {
bf.deleteCharAt(len - 1);
}
return bf.toString();
}
修改後如下:(同時支持多個號碼)
當然本項目也保留了掃碼功能(可在DecodeHandler
中自己添加條碼格式):
細心的同學可以從圖中看到掃描框的大小都不一樣,這裏我是改成了可以手動調節大小的掃描框。畢竟掃碼模式下,框大一點還是比較好識別(將二維碼放入框中有時就費時間)。掃數字這些文字時,框小一點會好識別。具體可以下載自行體驗。
最後我將代碼已經上傳至Github:Tesseract-OCR-Scanner,大家多點贊點星,感謝!!