項目地址
https://github.com/979451341/OrcTestgit
咱們說說實現這個項目已實現的功能,可以截圖手機界面的某一塊,將這個某一塊圖片的Bitmap傳給tess-two的代碼來獲取掃描結果github
我這裏在貼出tess-two這個專爲Android而建立的文字識別框架的地址
https://github.com/rmtheis/tess-two正則表達式
接下來我就說我如何一步一步的實現項目canvas
1.實現基礎界面,我這裏貼出已完成的界面併發
這樣是爲了模仿掃描二維碼的界面,由於掃描×××號碼或者是手機號那樣長條的數字,就將掃描區域也作成長條狀,這個掃描區域是有意義的,由於到時候截圖會只將掃描區域裏的圖片信息拿去掃描,這也是爲了提升掃描速度和精度。app
首先要實現這個界面,咱們須要畫出四個灰色長方體的位置大小,上下左右。框架
left是掃描區域左邊離手機屏幕左邊的距離是手機屏幕寬度的1/10,right就是掃描區域右邊離手機屏幕左邊的距離是手機屏幕寬度的9/10,top是掃描區域頂部離手機屏幕頂部的距離是手機屏幕寬度的1/3,bottom是掃描區域底部離手機屏幕頂部的距離是手機屏幕寬度的4/9ide
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); PMwidth = display.getWidth(); PMheight = display.getHeight(); left = PMwidth/10; top = PMheight/3; right = PMwidth*9/10; bottom = PMheight*4/9; mFrameRect = new Rect(left,top,right,bottom);
畫畫函數
@Override public void onDraw(Canvas canvas) { int width = PMwidth; int height = PMheight; Rect frame = mFrameRect; // 繪製焦點框外邊的暗色背景 mPaint.setColor(mMaskColor); canvas.drawRect(0, 0, width, frame.top, mPaint); canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, mPaint); canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, mPaint); canvas.drawRect(0, frame.bottom + 1, width, height, mPaint); }
尚未完,還有佈局文件放SurfaceView和按鈕,還有剛纔作的自定義View工具
2.顯示Camera預覽和Camera拍攝
這裏SurfaceView如何顯示Camera我很少說,只說如何把Camera預覽變清晰,這裏是經過循環自動對焦來完成。
設置自動對焦接口
mCamera.autoFocus(autoFocusCallback);
這個接口初始化傳入了Handler
autoFocusCallback.setHandler(handler,MSG_AUTOFUCS);
而後這個接口實現類裏,當完成自動對焦,會經過handler發送一個消息
@Override public void onAutoFocus(boolean success, Camera camera) { Log.v("zzw", "autof focus "+success); if (mAutoFocusHandler != null) { mAutoFocusHandler.sendEmptyMessageDelayed(mAutoFocusMessage,AUTO_FOCUS_INTERVAL_MS);
// mAutoFocusHandler = null;
} else {
Log.v(TAG, "Got auto-focus callback, but no handler for it");
}
}
而後handler如何執行如下代碼,再進行一次自動對焦,這樣就完成了循環
case MSG_AUTOFUCS: cameraUtil.autoFocus(); break;
而後給按鈕賦予拍攝功能,拍攝的還要中止聚焦
handler.removeCallbacksAndMessages(null); cameraUtil.takePicture(TwoActivity.this,TwoActivity.this,TwoActivity.this);
這個函數會被調用,data就是圖片數據
@Override public void onPictureTaken(byte[] data, Camera camera)
這裏要注意一件事,拍攝後Camera預覽界面就會中止,由於他中止聚焦了,咱們須要從新設置自動對焦,並開啓預覽
// 刷新相機 public void refreshCamera(){ if (surfaceHolder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch(Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { mCamera.setPreviewDisplay(surfaceHolder); mCamera.startPreview(); mCamera.autoFocus(autoFocusCallback); } catch (Exception e) { } surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); }
3.處理圖片數據,完成局部截圖
繼續在onPictureTaken函數的data數據處理
由於處理圖片是耗時任務,因此開啓子線程完成
這裏先開啓一個等待對話框
if(!mypDialog.isShowing()) mypDialog.show();
而後開啓子線程
if(data != null){ new Thread(new BitmapThread(bitmap,data,handler,TwoActivity.this)).start(); }
將data轉換爲Bitmap數據
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
將圖片旋轉90度
bitmap = rotateBitmap(bitmap,90);
這是旋轉Bitmap的函數
public static Bitmap rotateBitmap(Bitmap source, float angle) { Matrix matrix = new Matrix(); matrix.postRotate(angle); return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); }
切割Bitmap,將掃描區域的圖片切割出來
int PMwidth = bitmap.getWidth(); // 獲得圖片的寬,高 int PMheight = bitmap.getHeight(); int left = PMwidth/10; int top = PMheight/3; int right = PMwidth*9/10; int bottom = PMheight*4/9; int width = right - left; int height = bottom - top; Log.v("zzw",PMheight+" "+PMwidth); bitmap = Bitmap.createBitmap(bitmap, left, top, width, height, null, false);
4.掃描出結果
其實tess-two框架的使用很簡單,可是使用這個框架須要依靠訓練文件來完成掃描,我在res目錄下放了raw文件夾,裏面的eng_traineddata文件就是這個用途,可是咱們不能直接使用它們,咱們須要將他們複製到手機存儲裏
下面的代碼意思是在應用私有路徑裏建立tesseract/tessdata/eng.traineddata相關路徑的文件並使用輸入流將文件的數據讀出來,而後使用輸出流將數據傳入eng.traineddata文件
public static void initTessTrainedData(Context context){ if(initiated){ return; } File appFolder = context.getFilesDir(); File folder = new File(appFolder, tessdir); if(!folder.exists()){ folder.mkdir(); } tesseractFolder = folder.getAbsolutePath(); File subfolder = new File(folder, subdir); if(!subfolder.exists()){ subfolder.mkdir(); } File file = new File(subfolder, filename); trainedDataPath = file.getAbsolutePath(); Log.d(TAG, "Trained data filepath: " + trainedDataPath); if(!file.exists()) { try { FileOutputStream fileOutputStream; byte[] bytes = readRawTrainingData(context); if (bytes == null){ return; } fileOutputStream = new FileOutputStream(file); fileOutputStream.write(bytes); fileOutputStream.close(); initiated = true; Log.d(TAG, "Prepared training data file"); } catch (FileNotFoundException e) { Log.e(TAG, "Error opening training data file\n" + e.getMessage()); } catch (IOException e) { Log.e(TAG, "Error opening training data file\n" + e.getMessage()); } } else{ initiated = true; } }
好了再說說tess-two框架的使用
建立TessBaseAPI
TessBaseAPI tessBaseAPI = new TessBaseAPI();
關閉測試
tessBaseAPI.setDebug(true);
設置訓練數據路徑和識別文字是英文
tessBaseAPI.init(path, "eng");
設置白名單
tessBaseAPI.setVariable(TessBaseAPI.VAR_CHAR_WHITELIST, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
設置黑名單
tessBaseAPI.setVariable(TessBaseAPI.VAR_CHAR_BLACKLIST, "!@#$%^&*()_+=-[]}{;:'\"\\|~`,./<>?");
設置識別模式
tessBaseAPI.setPageSegMode(TessBaseAPI.PageSegMode.PSM_AUTO_OSD);
傳入bitmap數據
tessBaseAPI.setImage(bitmap);
獲取掃描結果
String inspection = tessBaseAPI.getHOCRText(0);
結束TestBaseAPI的使用
tessBaseAPI.end();
實現掃描×××號碼,這裏是經過正則表達式來判斷掃描出的結果是否有×××號碼,也就是說tess-two實際上是隻是掃描出Bitmap文件裏面有哪些文字,而後使用正則表達式來篩選出咱們須要的數據。也就是說咱們經過換取正則表達式就能作到掃描手機號等,帶有某種規律的數字或者字母
這是正則表達式的線上工具地址,你們能夠本身試試 http://tool.oschina.net/regex/#
private static Pattern pattern = Pattern.compile("\\d{17}[\\d|x]|\\d{15}"); public static String getTelNum(String sParam){ if(TextUtils.isEmpty(sParam)){ return ""; } 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(); }
而後經過handler返回結果
Message message = Message.obtain(); message.what = 1; Bundle bundle = new Bundle(); bundle.putString("decode",strDecode); message.setData(bundle); message.what = TwoActivity.MSG_BITMAP; handler.sendMessage(message);
取消加載框,並將局部截圖的圖像和掃描的結果經過DialogFragment顯示出來
mypDialog.dismiss(); String strDecode = msg.getData().getString("decode","掃描失敗"); if(strDecode == null ||strDecode.equals("")) strDecode = "掃描失敗"; imageDialogFragment.setImage(bitmap); imageDialogFragment.setText(strDecode); imageDialogFragment.show(getFragmentManager(), "ImageDialogFragment");
5.結論
其實尚未結束由於我本想作出一個可以掃描整張×××的項目,我看一下網上有不少API都能實現這個功能,但都要錢,若是要是可以實現這個功能,併發到github,我豈不是成爲大神了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。