项目地址
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);

画画

    @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,我岂不是成为大神了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

更多相关文章

  1. “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
  2. Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
  3. 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
  4. Android(安卓)基础知识4:四大组件之 ContentProvider(外共享数据)
  5. Android(安卓)串口通信
  6. android连接远程数据库教程1
  7. 20172314 2017-2018-2《程序设计与数据结构》第十一周学习总结
  8. Android(安卓)目前占据智能手机销售领域的主导地位
  9. Android(安卓)入门(7)——文件持久化存储

随机推荐

  1. Android中的资源分析
  2. Android独特的架构:HAL与Dalvik虚拟机
  3. android 属性系统使用的小问题
  4. Android 3.0,将为对战iPad归来
  5. Android 系列 5.9使用Inkscape创建Androi
  6. android 2.3 从零开始学习—环境的搭建以
  7. Android面试系列2018总结(全方面覆盖Andr
  8. Android和设计模式:模板模式
  9. [Android] Android进程和线程模型
  10. android就一定比java差?