array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 Android 识别身份证号码(图片识别) - demo例子集 - 爱码网
demodashi

Android 识别身份证号码(图片识别)

概述

Android 身份证号码识别 (本地,在线,实时),网络识别用的别人的接口,不保障什么时候就用不了了,本地识别基于tess_two,位置对的话识别准确率达到90%以上。

详细

 

前些天下午没什么事,朋友有个需求,说要识别身份证上面的身份证号码,刚好闲着,就帮他解决了一下,不说多完美,但是至少算是解决需求了,好了,闲话少说。

先来看一下我的DEMO吧

接下来我们一个个介绍

 

一、联网识别

也是从别人的Demo里截出来的,其实也是用的别人的一个在线接口,但是我看了看应该算“非正常调用”(这个意思大家自己理解吧)。下面分析一下这个方法的优劣点吧。

优点:速度极快,上传照片,会返回身份证上所有信息,包括姓名 地址 出生等等

缺点:“非正常”调用就有一定的不可靠性,如果哪天人家关了或者改了这个接口,就比较尴尬了,当然你可以选择购买人家的正式版。

二、本地识别

基于Tess_two做的识别,这个大家可放心使用。先看一下大概怎么使用吧!

 

首先引用:

compile \'com.rmtheis:tess-two:6.0.0\'

 

然后使用,其实使用起来很简单,但是要注意几点

 

1.要在SD卡有他的识别库,这个库你可以理解为一个字典,这个字典可以自己训练,因为我是用的别人训练好的(只包含英文和数字),所以就不说怎么训练了,百度一下会有很多。

2.需要注意的是,放他字典的路径文件夹名必须为“tessdata”,否则报错

好了,准备工作做好了,接下来介绍怎么使用,我直接贴核心代码,代码有注释,看不懂的留言或者私信我

//训练数据路径,tessdata
    static final String TESSBASE_PATH = Environment.getExternalStorageDirectory() + "/";
    //识别语言英文
    static final String DEFAULT_LANGUAGE = "eng";

    /**
     * 传SD卡图片路径(当然你们也可以传Bitmap)
     * @param url
     */
    private void localre(String url) {
        //把图片转为Bitmap
        Bitmap bmp = BitmapFactory.decodeFile(url);
        //创建Tess
        final TessBaseAPI baseApi = new TessBaseAPI();
        //下面这一块代码为裁取身份证号码区域(否则识别乱码,不准确)
        int x, y, w, h;
        x = (int) (bmp.getWidth() * 0.340);
        y = (int) (bmp.getHeight() * 0.800);
        w = (int) (bmp.getWidth() * 0.6 + 0.5f);
        h = (int) (bmp.getHeight() * 0.12 + 0.5f);
        Bitmap bit_hm = Bitmap.createBitmap(bmp, x, y, w, h);
        //这个只是我将裁取的号码区展示在了一个ImageView上,这个可以没有
        iv_number.setImageBitmap(bit_hm);
        //初始化OCR的训练数据路径与语言
        baseApi.init(TESSBASE_PATH, DEFAULT_LANGUAGE);
        //设置识别模式
        baseApi.setPageSegMode(TessBaseAPI.PageSegMode.PSM_SINGLE_LINE);
        //设置要识别的图片
        baseApi.setImage(bit_hm);
        //设置字典白名单
        baseApi.setVariable("tessedit_char_whitelist", "0123456789Xx");
        //把识别内容设置到EditText里
        tv_result.setText(baseApi.getUTF8Text());
        //收尾
        baseApi.clear();
        baseApi.end();
    }

OK,就这么简单,图片清晰切裁取区域正确的情况下,准确度几乎100%;

给大家举个身份证照片的例子吧,否则裁取号码会不

 

上一张结果图

实时识别

 

其实就是本地识别的拓展版,把摄像头的数据转为Bitmap,去识别,还是贴核心代码吧,看不懂的自己下Demo研究。

/**
     * 摄像头数据回调
     * @param data
     * @param camera
     */
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        camera.addCallbackBuffer(data);
        //将byte数组转为Bitmap
        ByteArrayOutputStream baos;
        byte[] rawImage;
        Bitmap bitmap;
        Camera.Size previewSize = camera.getParameters().getPreviewSize();//获取尺寸,格式转换的时候要用到
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;
        YuvImage yuvimage = new YuvImage(
                data,
                ImageFormat.NV21,
                previewSize.width,
                previewSize.height,
                null);
        baos = new ByteArrayOutputStream();
        yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 100, baos);// 80--JPG图片的质量[0-100],100最高
        rawImage = baos.toByteArray();
        //将rawImage转换成bitmap
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length, options);
        if (bitmap == null) {
            Log.d("zka", "bitmap is nlll");
            return;
        } else {
            //裁取图片中央身份证区域
            int height = bitmap.getHeight();
            int width = bitmap.getWidth();
            final Bitmap bitmap1 = Bitmap.createBitmap(bitmap, width/2 - dip2px(150),height / 2 - dip2px(92), dip2px(300), dip2px(185));
            //截取身份证号码区域
            int x, y, w, h;
            x = (int) (bitmap1.getWidth() * 0.340);
            y = (int) (bitmap1.getHeight() * 0.800);
            w = (int) (bitmap1.getWidth() * 0.6 + 0.5f);
            h = (int) (bitmap1.getHeight() * 0.12 + 0.5f);
            Bitmap bit_hm = Bitmap.createBitmap(bitmap1, x, y, w, h);
           // 识别
            if(bit_hm != null){
                String localre = localre(bit_hm);
                if (localre.length() == 18) {
                    Log.e(TAG, "onPreviewFrame: "+localre );
                    Toast.makeText(getApplicationContext(),localre,Toast.LENGTH_SHORT).show();
                }
            }
        }
    }


    /**
     * 识别
     * @param bm
     * @return
     */
    private String localre(Bitmap bm) {
        String content = "";
        bm = bm.copy(Bitmap.Config.ARGB_8888, true);
        iv_result.setImageBitmap(bm);
        TessBaseAPI baseApi = new TessBaseAPI();
        baseApi.init(TESSBASE_PATH, DEFAULT_LANGUAGE);
        //设置识别模式
        baseApi.setPageSegMode(TessBaseAPI.PageSegMode.PSM_SINGLE_LINE);
        //设置要识别的图片
        baseApi.setImage(bm);
        baseApi.setVariable("tessedit_char_whitelist", "0123456789Xx");
        Log.e(TAG, "localre: "+ baseApi.getUTF8Text());
        content = baseApi.getUTF8Text();
        baseApi.clear();
        baseApi.end();
        return content;
    }

三、源码包截图

blob.png

四、其他

Ok,就这样吧!核心也就这些东西,有问题的可以留言或私信,有好的解决办法也可以交流,,出于隐私,就把人家的信息打码, 不过识别出来准确度是100%。

 

 

 

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

 

分类:

技术点:

相关文章: