zxing和opencv實現身份識別

*

**轉自: http://blog.csdn.net/sinat_28891771/article/details/71191777?locationNum=2&fps=1**

*

實現原理分析 :通過zxing庫捕捉相機獲得圖像,或者從相冊裏獲取圖片,再對圖像進行處理. 對圖像處理 : 對源圖像進行像素放大縮小處理>預處理(圖像灰度化,低通濾波處理,邊緣檢測,二值化,中值平滑處理,閉運算)>刷選身份證號的矩形,得到有效行>對有效行進行灰度化,二值化>然後就進行識別.

實現過程:
1. 環境的配置
a. opencv3.2的依賴: 去官網下載opencv for android的sdk,解壓得到這個目錄

在android studio中選擇improt module加載進來 將依賴的opencv的build.gradle裏的版本要求和主工程的build.gradle保持一致如圖

最後將sdk目錄中的native的libs裏的文件複製到主工程的main裏的jniLibs目錄下,jniLibs目錄需自己創建.這樣opencv庫就裝載成功了!

b. tesseract庫的使用,本文章不對tesseract如何編譯做詳細介紹,可以使用tess-two,有編譯好的,解壓的後,把Jar文件添加到項目,把libs目錄的文件複製到jniLibs目錄下這樣tess-two就集成完了.

c. 語言包的放置,可以從tesseract-ocr的官網下載中文的或者英文的,但是針對只是身份證號的識別,打算自己訓練,官方下載的語言包文件都過大,本篇文章不對如何訓練做詳細介紹.

d. zxing庫的引用(本文不做介紹)

2 代碼實現
如圖
如上圖主界面爲三個入口,根據的scan_type的類型來調用zxing庫的掃描類型
這裏寫圖片描述

在Zxing庫的CaptureActivity類做以下添加:

//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的方法裏添加

    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類裏同二維碼識別一樣,將相機捕捉的圖像進行解析

  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類和CoreUtil類的介紹

IdCardIdentify類中的idCardIdentify方法,參數有activity和相機捕捉的bitmap.

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目錄下,再對源圖像進行比例方法縮小,然後將圖像預處理,即找到號碼的位置,最後將號碼的位置進行識別

圖像的預處理:

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;
} 

將圖像進行形態學相關的處理,最後刷選連通域的矩形來確定號碼的位置,如果沒有找到的話,就根據身份證的位置特徵進行切割

圖像預處理第二步


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;
}

最後一步識別
/**
* 對要識別的圖像進行識別
*
* @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;

}     

效果展示:
圖一

效果

圖二

效果

圖三

效果

圖四

效果
所使用身份證素材均來自百度搜索

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章