Android tesseract-orc之扫描身份证号码

踩了不少坑,终于把这个扫描版的身份证识别做出来了,图片识别引擎用的是tesseract,在已经训练好样本的情况下,感觉识别率还是一般般~ 
下面说一说大概几个坑、

一、 编译tesseract-orc Android版本 
首先你需要Android-ndk工具,Android ndk开发,我们这里不做开发,只需要编译tesseract变成so文件、tesseract Android版下载地址,这里只需要编译tesseract-two这个项目、编译方法在那篇博客说的很清楚了,编译时间有点久(耐心等待,并且大部分人在这里会扑街)

二、测试是否编译成功 
新建一个项目,用引用类库的方式引用tesseract-two,API的调用方法也很简单:

TessBaseAPI baseApi=new TessBaseAPI();
//这里进行初始化,第一个参数是训练语言的路径,第二个参数的语言名字,后面我们的训练文件都要放在这里面,这里可以先用eng代替下测试、
baseApi.init(TESSBASE_PATH, DEFAULT_LANGUAGE);
baseApi.setPageSegMode(TessBaseAPI.PSM_AUTO);
//这里把图片放进去进行了
baseApi.setImage(bitmap);
final String outputText = baseApi.getUTF8Text();
Log.i(TAG, "识别结果:" + outputText);
baseApi.end();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上述就是整个API的调用流程,值得注意的是,该流程是一个耗时操作,不可在UI线程中调用、 
若没有闪退,并且有大概的识别文字出来,表示编译成功,接下来就开始训练新语言。

三、训练新语言,提高识别率 
说到训练语言这个问题,网上的文章是非常多的,不过我却在这里卡了很久,原因是因为网上大部分文章是针对3.01版本训练,而现在版本是3.02,有几个地方死活报错过不去、寻其原因在于文件名的问题!tesseract-orc3.02训练方法 这篇博客已经说的很清楚啦,我再把精简一下: 
图片名字的格式 一定需要按照 [lang].[fontname].exp[num].tif 该格式!用id.custom.exp0.tif 作为示范

1).转成 tif 格式图片,用jTessBoxEditor工具 合成为一张tif图片

2).生成box文件,调用命令行: 
tesseract id.custom.exp0.tif id.custom.exp0 batch.nochop makebox

3).利用jTessBoxEditor工具,对文件进行编辑,校正,得到新的box文件

4).生成.tr文件,调用命令行: 
tesseract id.custom.exp0.tif id.custom.exp0 nobatch box.train

5).生成字符集,调用命令行: 
unicharset_extractor id.custom.exp0.box

6).设置字体,新建文本文件font_properties,里面输入字体信息,内容格式为: 
第一个fontname 一定要对应之前文件的名字, 这里输入 custom 0 1 0 0 0 ,表示是加粗字体格式

7).接下来,进行聚合,分别调用三句命令: 
shapeclustering -F font_properties -U unicharset id.custom.exp0.tr 
mftraining -F font_properties -U unicharset -O id.unicharset id.custom.exp0.tr 
cntraining id.custom.exp0.tr id.custom.exp0.tr

8).把生成第7步生成的4个文件加入前缀“id.”(),调用命令行,生成最终数据 
combine_tessdata id. (别漏掉了.) 
type 1,type3, type4, type5对应的后面数据如果不是-1,就表示这次训练成功!

9).进行测试: 
tesseract id1.jpg output -l id

四、集成到项目中实现拍照识别 
如果上述训练没有问题,那么可以将训练文件 id.traineddata 放在assert文件夹中,当应用程序启动时,将其拷贝到sd卡,这里值得注意的是,拍照返回的图片都比较大,是需要进行压缩的、最终大小尽量和你训练时的大小一致,然后图片进行灰度处理,再调用API来识别。

五、扫描识别 
由于拍照后再识别的准确率实在是低,和拍照的角度,光线,以及拍照时身份证没有填满照片等等因素,很难做到高准确率的识别、于是我就仿造扫描二维码(支付宝扫描银行卡号)的方式,来增加识别次数提高识别率。扫描界面我是借鉴二维码扫描的代码、大致流程: 
需要一个Camera对象来获取相机资源,用一个SurfaceView来显示相机预览,surfaceview启动时获取相机资源,并且实现自动对焦和预览回调接口,自动对焦是定时的,每过1.5秒对焦一次、而在预览回调接口中:

    /**
     * 拍照回调
     */
    PreviewCallback previewCallback = new PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            // TODO Auto-generated method stub
            if (isChoice) {
                new MyOrcTask().execute(data);
                isChoice = false;
            }

        }
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我们把图片处理,图片识别放在了异步任务中,因为该接口是不停的回调的、每次传进一张照片进入后,把标志改为false,当异步任务执行完后,把标志改为true,这样就是单线程异步的执行图片识别任务、

/**
     * 图片解析的异步任务!
     *
     * @author kaifa
     *
     */
    class MyOrcTask extends AsyncTask<byte[], Void, Void> {

        String text = "";

        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(byte[]... params) {
            // TODO Auto-generated method stub
            byte[] data = params[0];

            Size size = camera.getParameters().getPreviewSize();
            try {
                YuvImage image = new YuvImage(data, ImageFormat.NV21,
                        size.width, size.height, null);
                if (image != null) {
                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    image.compressToJpeg(
                            new Rect(0, 0, size.width, size.height), 80, stream);
                    Bitmap bitmap = BitmapFactory.decodeByteArray(
                            stream.toByteArray(), 0, stream.size());

                    bitmap = Bitmap.createBitmap(bitmap, x, y, width, height);
                    // 去解析
                    if (bitmap != null) {

                        bitmap = comp(bitmap);
                        bitmap = ImageFilter.grayScale(bitmap);
                        TessBaseAPI baseAPI = new TessBaseAPI();
                        // 初始化
                        baseAPI.init(TESSBASE_PATH, DEFAULT_LANGUAGE);
                        baseAPI.setPageSegMode(TessBaseAPI.PageSegMode.PSM_AUTO);

                        baseAPI.setImage(bitmap);

                        text = baseAPI.getUTF8Text();

                        baseAPI.end();
                    }

                    stream.close();

                }
            } catch (Exception ex) {
                Log.e("Sys", "Error:" + ex.getMessage());
            }

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            text.replaceAll("\n", "");
            text = text.trim();
            if (text.length() > 18) {
                text = text.substring(text.length() - 18, text.length());
                if (IDcheckClassUtil.validateIdCard18(text)) {
                    Toast.makeText(ScanActivity.this, "成功!请核对", 0).show();
                    isChoice = false;
                    textView.setText(text);
                    } else {
                    // Toast.makeText(ScanActivity.this, "就差一点点啦!", 0).show();
                    isChoice = true;
                }

            } else {
                // Toast.makeText(ScanActivity.this, "请再对齐一点点哦!", 0).show();
                // 继续去选择图片
                isChoice = true;
            }

        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

很多人都要代码,源码在这~

原文地址:https://www.cnblogs.com/Alex80/p/9074948.html

时间: 2024-10-15 07:31:14

Android tesseract-orc之扫描身份证号码的相关文章

Android 身份证号码查询、手机号码查询、天气查询

1.基本信息 身份证号码查询:http://apistore.baidu.com/apiworks/servicedetail/113.html 手机号码:http://apistore.baidu.com/apiworks/servicedetail/117.html 天气查询http://apistore.baidu.com/apiworks/servicedetail/112.html 2.运行效果       

iOS身份证号码识别

一.前言 ??身份证识别,又称OCR技术.OCR技术是光学字符识别的缩写,是通过扫描等光学输入方式将各种票据.报刊.书籍.文稿及其它印刷品的文字转化为图像信息,再利用文字识别技术将图像信息转化为可以使用的计算机输入技术. ??因为项目需要,所以这些天查阅了相关资料,想在网上看看有没有大神封装的现成的demo可以用.但是无果,网上关于ocr这一块的资料很少,比较靠谱的都是要收费的,而且价格也不便宜.但是在天朝,收费感觉心里不爽,所以就决定自己研究一番. ??先上一个最终实现的效果(如果mac不是r

[置顶] JAVA识别身份证号码,H5识别身份证号码,tesseract-ocr识别(一)(转)

背景介绍: 这段时间正在做一个流动人口管理项目,其中要求使用H5网页拍照识别身份证,当时就蒙圈了,这不是APP的功能吗?产品为了快速迭代一直把APP的功能往H5上堆砌,没办法只有想办法解决了. 查了一些资料,发现除了收费的OCR(百度.云脉等等)比较好的并支持中文的就只有tesseract了,当然我收费的OCR我也没测试. 暂时决定使用tesseract了. 思路介绍 我的思路是这样的: 由H5调用摄像头—–>拍照上传到服务端—->服务端识别身份信息—–>服务端返回身份信息. 关键点提高

【HR必看】Excel中对身份证号码的处理技巧

[HR必看]Excel中对身份证号码的处理技巧 身份证号码的处理是HR部门经常遇到的问题,我给几个地方的企业培训时发现,相当一部分人员基本还是手动对身份证号码进行处理,效率可想而知啦!下面,刘老师为大家深入讲解Excel中,与身份证号码处理相关的方方面面. 一.录入技巧 1.手动输入问题与解决方法 问题:在Excel中输入身份证号码时,发现输入后变成了科学计数格式,如图: 使用单引号" ' "强制转成文本类型,发现后三位竟然全变成了0. 咋办呢? 原因:Excel中输入大于11位数字时

身份证号码图像提取--基于canny边缘检测的连通域检测算法

在之前扫描二维码提取任务之后,工作中又需要将身份证图像中的身份证号码提取出来,然后给同事调用进行识别.之前的连通域检测算法比较"蛮力",因为它一旦检测出一个大的区域,那么这区域中的所有内部区域都将不复存在了.所以在连通域检测时,需要第一步去掉周围可能存在的白边,否则就会失败.后来笔者换了一个思路,如果检测一个区域时保存对应生成该区域的点,该区域不符合要求的话就将这些点擦掉,从而就不会影响到内部的区域了.于是就有了一下算法的诞生: (1)从左上角开始,从碰到的第一个白点开始探测最大的连通

我用python算出了同事的身份证号码!

作者:朱小五 来源:凹凸玩数据 事情的经过是这样的: 我的同事李大伟最近出差去了. 昨晚睡觉前翻了翻朋友圈, 就跟他愉快地 互怼 交流了起来. 估计是他想起了我朱小五从不打无把握之赌,后面就怂了. 一杯奶茶嘛,也可以接受, 像杰伦一样快乐就好啦. 开工. 先看看李大伟的朋友圈中发的图片. (该火车票来自其他平行世界,扫描可能发生奇怪现象) 车票中暴露的个人信息为: 3302211993****4914 李大伟 只缺少月份日期四位. 那么也就是一共365种可能. 科普时间: 根据李大伟的身份证信息

算法提高 身份证号码升级

问题描述 从1999年10月1日开始,公民身份证号码由15位数字增至18位.(18位身份证号码简介).升级方法为: 1.把15位身份证号码中的年份由2位(7,8位)改为四位. 2.最后添加一位验证码.验证码的计算方案: 将前 17 位分别乘以对应系数 (7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2) 并相加,然后除以 11 取余数,0-10 分别对应 1 0 x 9 8 7 6 5 4 3 2. 请编写一个程序,用户输入15位身份证号码,程序生成18位身份证号码.假设所

例题:输入身份证号码,判断你是什么生肖。switch,case练习,substring 类使用联系,会用取余

Console.WriteLine("请输入您的身份证号码"); string x = Console.ReadLine(); string year=x.Substring (6,4);//从身份证的第六位开始截取,往后截取四位,就是你的出生年份 int x1 = Convert.ToInt32(year);//把截取到年份代入到x1中, string sx = ""; switch(x1%12)//输入一个年份取余,如果假设取余为四,你能判断那年的生肖,然后根据

使用Excel的函数批量判断身份证号码是否有效

一.描述 现在有一个批量上传用户的需求,其中需要上传用户名.姓名和身份证号码,进行实名批量注册,如何能快速判断用户给的身份证号是否格式正确呢?其实无论是WPS的excel还是Microsoft office中的excel都提供了函数功能,我们只要在单元中调用一定的函数就可以判断该身份证是否符合要求,如果符合,就输出Right,错误就输出Wrong. 二.源代码 =IF(LOOKUP((LEFT(C2,1)*7+MID(C2,2,1)*9+MID(C2,3,1)*10+MID(C2,4,1)*5+