android|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|zxing和opencv实现身份识别
文章图片

在android studio中选择improt module加载进来 将依赖的opencv的build.gradle里的版本要求和主工程的build.gradle保持一致android|zxing和opencv实现身份识别
文章图片

最后将sdk目录中的native的libs里的文件复制到主工程的main里的jniLibs目录下,jniLibs目录需自己创建.这样opencv库就装载成功了!
b. tesseract库的使用,本文章不对tesseract如何编译做详细介绍,可以使用tess-two,有编译好的,解压的后,把Jar文件添加到项目,把libs目录的文件复制到jniLibs目录下这样tess-two就集成完了.
c. 语言包的放置,可以从tesseract-ocr的官网下载中文的或者英文的,但是针对只是身份证号的识别,打算自己训练,官方下载的语言包文件都过大,本篇文章不对如何训练做详细介绍.
d. zxing库的引用(本文不做介绍)
2 代码实现
android|zxing和opencv实现身份识别
文章图片

如上图主界面为三个入口,根据的scan_type的类型来调用zxing库的扫描类型
android|zxing和opencv实现身份识别
文章图片

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

效果展示:
android|zxing和opencv实现身份识别
文章图片

android|zxing和opencv实现身份识别
文章图片

【android|zxing和opencv实现身份识别】android|zxing和opencv实现身份识别
文章图片

android|zxing和opencv实现身份识别
文章图片

android|zxing和opencv实现身份识别
文章图片

android|zxing和opencv实现身份识别
文章图片

android|zxing和opencv实现身份识别
文章图片

android|zxing和opencv实现身份识别
文章图片

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

    推荐阅读