項目地址
https://github.com/979451341/OrcTest
我們說說實現這個項目已實現的功能,能夠截圖手機界面的某一塊,將這個某一塊圖片的Bitmap傳給tess-two的代碼來獲取掃描結果
我這里在貼出tess-two這個專為Android而創建的文字識別框架的地址
https://github.com/rmtheis/tess-two
接下來我就說我如何一步一步的實現項目
1.實現基礎界面,我這里貼出已完成的界面
這樣是為了模仿掃描二維碼的界面,因為掃描身份證號碼或者是手機號那樣長條的數字,就將掃描區域也做成長條狀,這個掃描區域是有意義的,因為到時候截圖會只將掃描區域里的圖片信息拿去掃描,這也是為了提高掃描速度和精度。 首先要實現這個界面,我們需要畫出四個灰色長方體的位置大小,上下左右。
left是掃描區域左邊離手機屏幕左邊的距離是手機屏幕寬度的1/10,right就是掃描區域右邊離手機屏幕左邊的距離是手機屏幕寬度的9/10,top是掃描區域頂部離手機屏幕頂部的距離是手機屏幕寬度的1/3,bottom是掃描區域底部離手機屏幕頂部的距離是手機屏幕寬度的4/9
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);
畫畫
@Overridepublic 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發送一個消息
@Overridepublic 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就是圖片數據
@Overridepublic void onPictureTaken(byte[] data, Camera camera)
這里要注意一件事,拍攝后Camera預覽界面就會停止,因為他停止聚焦了,我們需要重新設置自動對焦,并開啟預覽
// 刷新相機public void refreshCamera(){if (surfaceHolder.getSurface() == null){// preview surface does not existreturn;}// stop preview before making changestry {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 settingstry {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,我豈不是成為大神了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
總結
以上是生活随笔 為你收集整理的Android ORC文字识别之识别身份证号等(附源码) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。