基于opencv库,tess-two,Zxing在Android

作者: 06fd4cf1f427 | 来源:发表于2019-01-11 17:53 被阅读10次

    提到“人工智能”这一名词,大多数人脑海中浮现的是机器人在忙碌着,我们偷懒似的生活着:我们购物不再走路,吃饭不再动手。“能动嘴我们绝不动手”这句话用在这里最好不过了。这样的生活理念是时代造就的,并不属于历史遗留问题。

    在科技未达到如此高的境界时,我们应该先关注一下身边的人工智能:Android端身份证识别。为什么我会提到这个名词呢?随着移动终端(智能手机及平板电脑)的普及,几乎人人都有一部手机已经毋庸置疑了。进而也引发了移动应用爆发似的浪潮,各类APP应接不暇:金融类的、办公类的、电商类的等等。这些应用大多会涉及到身份证的实名认证。如果让用户手动输入信息,显然不符合时代背景,必然会流失一大批“粉丝”。

    基于opencv库和tess-two,Zxing在android平台上实现身份证号的识别!

    实现原理分析 :通过zxing库捕捉相机获得图像,或者从相册里获取图片,再对图像进行处理. 对图像处理 : 对源图像进行像素放大缩小处理>预处理(图像灰度化,低通滤波处理,边缘检测,二值化,中值平滑处理,闭运算)>刷选身份证号的矩形,得到有效行>对有效行进行灰度化,二值化>然后就进行识别.

    一. 环境的配置

    **1. **opencv3.2的依赖: 去官网下载opencv for android的sdk,解压得到。

    在android studio中选择improt module加载进来 将依赖的opencv的build.gradle里的版本要求和。

    主工程的build.gradle保持一致。

    最后将sdk目录中的native的libs里的文件复制到主工程的main里的jniLibs目录下,jniLibs目录需自己创建.这样opencv库就装载成功了!

    2. tesseract库的使用,本文章不对tesseract如何编译做详细介绍,可以使用tess-two,有编译好的,解压的后,把Jar文件添加到项目,把libs目录的文件复制到jniLibs目录下这样tess-two就集成完了。

    3. 语言包的放置,可以从tesseract-ocr的官网下载中文的或者英文的,但是针对只是身份证号的识别,打算自己训练,官方下载的语言包文件都过大,本篇文章不对如何训练做详细介绍.

    4. zxing库的引用(本文不做介绍)

    二、代码实现

    image

    如上图主界面为三个入口,根据的scan_type的类型来调用zxing库的扫描类型 :

    在Zxing库的CaptureActivity类做以下添加:

    <pre style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word;">

    //OpenCV库加载并初始化成功后的回调函数
    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
    
     @Override
     public void onManagerConnected(int status) {
     // TODO Auto-generated method stub
     switch (status) {
     case BaseLoaderCallback.SUCCESS:
     Log.i(TAG, "成功加载");
     break;
     default:
     super.onManagerConnected(status);
     Log.i(TAG, "加载失败");
     break;
     }
     }
    };
    
    

    在onResume的方法里添加

    <pre style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word;">

     if (!OpenCVLoader.initDebug()) {
     Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for 
     initialization");
     OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_2_0, this, 
     mLoaderCallback);
     } else {
     Log.d(TAG, "OpenCV library found inside package. Using it!");
     mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
     }
    
    

    这个opencv库初始化加载回调和onResume方法里添加的判断是一定要添加的。

    其它细节不做详细介绍,后面会将源码发布!

    在zxing库的DecodeHandler类里同二维码识别一样,将相机捕捉的图像进行解析

    <pre style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word;">

     if (scan_type.equals(CaptureActivity.SCAN_TYPE_QRCODESCAN)) {
     rawResult = multiFormatReader.decodeWithState(bitmap);//解析二维 
     码图片
     } else if (scan_type.equals(CaptureActivity.SCAN_TYPE_BANK_CARD)) {
     result = BankCardIdentify.bankCardIdentify(activity,toBitmap(source, 
     source.renderCroppedGreyscaleBitmap()));//解析银行卡
     } else {
     result = IdCardIdentify.idCardIdentify(activity, toBitmap(source, 
     source.renderCroppedGreyscaleBitmap())); //解析身份证
     }
    
    

    IdCardIdentify类中的idCardIdentify方法,参数有activity和相机捕捉的bitmap.

    <pre style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word;">

    public static String idCardIdentify(Activity activity, Bitmap bitmap) {
     CoreUtil.copyToSD(activity);
     bitmap = CoreUtil.scaleImage(bitmap, 900, 450); //根据像素放大缩小图片
     bitmap = ICPretreatment.doICPretreatmentOne(bitmap);//图像预处理
     CoreUtil.saveBitmap(bitmap);
     return getResult(ICPretreatment.doICPretreatmentTwo(bitmap)); //返回有效
     行识别结果
    } 
    
    

    先加载语言包文件,将assets目录下的语言包文件保存到sd目录下,再对源图像进行比例方法缩小,然后将图像预处理,即找到号码的位置,最后将号码的位置进行识别。

    图像的预处理:

    <pre style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word;">

    public static Bitmap doICPretreatmentOne(Bitmap bitmap) {
     Mat rgbMat = new Mat(); //原图
     Mat grayMat = new Mat(); //灰度图
     Mat binaryMat = new Mat(); //二值化图
     Mat canny = new Mat();
     Utils.bitmapToMat(bitmap, rgbMat);
     Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);//灰度化
     Imgproc.blur(grayMat, canny, new Size(3, 3));//低通滤波处理
     Imgproc.Canny(grayMat, canny, 125, 225);//边缘检测处理类
     Imgproc.threshold(canny, binaryMat, 165, 255, Imgproc.THRESH_BINARY);//二值化
     Imgproc.medianBlur(binaryMat, binaryMat, 3);//中值平滑处理
     Mat element_9 = new Mat(20, 20, CV_8U, new Scalar(1));
     Imgproc.morphologyEx(binaryMat, element_9, MORPH_CROSS, element_9);//闭运算
     /**
     * 轮廓提取()
     */
     ArrayList<MatOfPoint> contoursList = new ArrayList<>();
     Mat hierarchy = new Mat();
     Imgproc.findContours(element_9, contoursList, hierarchy, 
     Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_NONE);
     Mat resultImage = Mat.zeros(element_9.size(), CV_8U);
     Imgproc.drawContours(resultImage, contoursList, -1, new Scalar(255, 0, 255));
     Mat effective = new Mat(); //身份证位置
     //外包矩形区域
     for (int i = 0; i < contoursList.size(); i++) {
     Rect rect = Imgproc.boundingRect(contoursList.get(i));
     if (rect.width != rect.height && rect.width / rect.height > 8) { //初步判断找 
     到有效位置 Imgproc.rectangle(resultImage, new Point(rect.x, rect.y), 
     new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(255, 0, 
     255), 1);effective = new Mat(rgbMat, rect);
     }
     }
     if (effective != null && effective.cols() > 0 && effective.rows() > 0) {bitmap = 
     Bitmap.createBitmap(effective.cols(),effective.rows(),Bitmap.Config.RGB_565);
     Utils.matToBitmap(effective, bitmap);
     } else {
     bitmap = CoreUtil.cropBitmap(bitmap, 280, 360, 600, 70, true);
     }
     return bitmap;
    } 
    
    

    将图像进行形态学相关的处理,最后刷选连通域的矩形来确定号码的位置,如果没有找到的话,就根据身份证的位置特征进行切割

    二、图像预处理第二步

    <pre style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word;">

    public static Bitmap doICPretreatmentTwo(Bitmap bitmap) { 
    Mat rgbMat = new Mat(); //原图 
    Mat grayMat = new Mat(); //灰度图 
    Mat binaryMat = new Mat(); //二值化图 
    Utils.bitmapToMat(bitmap, rgbMat); 
    Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);//灰度化 
    Imgproc.threshold(grayMat, binaryMat, 150, 255, Imgproc.THRESH_BINARY);//二值化 
    bitmap = Bitmap.createBitmap(binaryMat.cols(), binaryMat.rows(), Bitmap.Config.RGB_565); 
    Utils.matToBitmap(binaryMat, bitmap); 
    return bitmap; 
    }
    
    

    三、最后一步识别

    <pre style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word;">

    /** 
    * 对要识别的图像进行识别 
    * 
    * @param bitmap 要识别的bitmap 
    * @return 
    */ 
    public static String getResult(Bitmap bitmap) { 
    String result; 
    TessBaseAPI baseApi = new TessBaseAPI(); 
    baseApi.setDebug(true); 
    baseApi.init(DATAPATH, “identify”); 
    bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); 
    baseApi.setImage(bitmap); 
    baseApi.setVariable(“tessedit_char_whitelist”, “0123456789X”); 
    result = baseApi.getUTF8Text(); 
    result = result.replaceAll(“\s*”, “”); 
    if (result.equals(“”) || result.length() <= 16 || result.length() >= 20) { //允许4个字符的误差 
    result = null; 
    } 
    baseApi.end(); 
    bitmap.recycle(); 
    return result;
    
    

    四、效果展示

    所使用身份证素材来自百度搜索

    如上的效果,发现经自己训练的语言包进行识别,识别率是很高的!


    【附】相关架构视频资料

    https://pan.baidu.com/s/1ZJFGCN3TKhTHMv9PyVCgsA

    资料领取

    关注我后台私信回复【干货分享】

    领取获取往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术

    相关文章

      网友评论

        本文标题:基于opencv库,tess-two,Zxing在Android

        本文链接:https://www.haomeiwen.com/subject/ccxfdqtx.html