zoukankan      html  css  js  c++  java
  • Android tesseract-orc之扫描身份证号码

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

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

    二、測试是否编译成功
    新建一个项目,用引用类库的方式引用tesseract-two。API的调用方法也非常easy:

    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();

    上述就是整个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;
                }
    
            }
        };

    我们把图片处理。图片识别放在了异步任务中,由于该接口是不停的回调的、每次传进一张照片进入后,把标志改为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(" ", ""); 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; } } }

    非常多人都要代码。源代码在这~

  • 相关阅读:
    C++11并发之std::thread<转>
    YUV420格式解析<转>
    在windows、linux中开启nginx的Gzip压缩大大提高页面、图片加载速度<转>
    curl 超时设置<转>
    C++中map用法详解《转》
    同一台服务器配置多个tomcat服务的方法
    找出两个排好序的数组的中位数
    mysql中设置默认字符编码为utf-8
    大步小步攻击算法_完全版
    ACL登陆认证
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7261920.html
Copyright © 2011-2022 走看看