赞
踩
这样是为了模仿扫描二维码的界面,因为扫描身份证号码或者是手机号那样长条的数字,就将扫描区域也做成长条状,这个扫描区域是有意义的,因为到时候截图会只将扫描区域里的图片信息拿去扫描,这也是为了提高扫描速度和精度。
首先要实现这个界面,我们需要画出四个灰色长方体的位置大小,上下左右。
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);
画画
- @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
这里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); }
继续在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);
其实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");
其实还没有结束因为我本想做出一个能够扫描整张身份证的项目,我看一下网上有很多API都能实现这个功能,但都要钱,如果要是能够实现这个功能,并发到github,我岂不是成为大神了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。