1.什么是身份证识别
身份证识别是指使用技术对身份证信息自动提取,并对身份证信息按要素格式化输出信息,供计算机系统管理。
目前身份证识别技术上有两种方式:
1、传统读卡器识别;
2、利用OCR技术识别,通过移动终端摄像头对身份证拍照,采集身份证信息。
接下来的要说的就是利用OCR技术识别身份证号码并抽取以及转化成文字显示
2.废话不都说,上demo运行演示
3.主要使用技术
1.C++层使用的是opencv,主要是图形图像处理
2.java层使用的是google 提供的tess-two
) ,主要是光学字符识别
4.原理
4.1.身份证识别流程图
4.2.什么是灰度化
将彩色图像转化成为灰度图像的过程称为图像的灰度化处理。
灰度化:在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色(比如#AAAAAA和#333333的颜色显示都是灰色系列),其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。
彩色图像中的每个像素的颜色有R、G、B三个分量决定,而每个分量有255个值可取,这样一个像素点可以有1600多万(255255255)的颜色的变化范围。而灰度图像一个像素点的变化范围为255种,所以在数字图像处理中一般先将各种格式的图像转变成灰度图像以使后续的图像的计算量变得少一些。灰度图像的描述与彩色图像一样仍然反映了整幅图像的整体和局部的色度和亮度等级的分布和特征。
4.3.彩色图像进行灰度化处理方法:分量法、最大值法、平均值法、加权平均法。
转摘处:https://www.jianshu.com/p/6d7539edad97
4.3.1. 分量法
将彩色图像中的三分量的亮度作为三个灰度图像的灰度值,可根据应用需要选取一种灰度图像。
f1(i,j)=R(i,j)
f2(i,j)=G(i,j)
f3(i,j)=B(i,j)
其中fk(i,j)(k=1,2,3)为转换后的灰度图像在(i,j)处的灰度值。
4.3.2. 最大值法
将彩色图像中的三分量亮度的最大值作为灰度图的灰度值。
f(i,j)=max(R(i,j),G(i,j),B(i,j))
4.3.3. 平均值法
将彩色图像中的三分量亮度求平均得到一个灰度值。
f(i,j)=(R(i,j)+G(i,j)+B(i,j)) /3
4.3.4. 加权平均法
根据重要性及其它指标,将三个分量以不同的权值进行加权平均。由于人眼对绿色的敏感最高,对蓝色敏感最低,因此,按下式对RGB三分量进行加权平均能得到较合理的灰度图像。
f(i,j)=0.30R(i,j)+0.59G(i,j)+0.11B(i,j))
4.3.5.Opencv对图像灰度化处理
在Opencv中可以通过以上几种方法的数值计算来得到灰度图像也可以通过opencv提供的颜色空间转换函数来得到。
Opencv封装灰度法
//灰度化
cvtColor(src_img, dst_img, COLOR_BGR2GRAY);
5.图像二值化
图像二值化( Image Binarization)就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程。
Opencv对图像二值化处理: 这里获取的是100~255
cv::threshold(dst, dst, 100, 255, CV_THRESH_BINARY);
6.腐蚀膨胀(简单理解)
膨胀算法使图像扩大一圈。
腐蚀算法使二值图像减小一圈。
腐蚀:删除对象边界的某些像素
膨胀:给图像中的对象边界添加像素
//加水膨胀,发酵
Mat erodeElement = getStructuringElement(MORPH_RECT, Size(20, 10));
erode(dst, dst, erodeElement);
7.轮廓检测
说白了,就是将符合检测的图片区域检测出来并裁剪
vector< vector<Point> > contours;
vector<Rect> rects;
//opencv提供的检测方法
cv:: findContours(dst, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
for (int i = 0; i < contours.size(); i++) {
Rect rect = boundingRect(contours.at(i));
if (rect.width > rect.height * 9) {
//满足width:height>9:1就放在rects集合中
rects.push_back(rect);
// 在dst 图片上显示 rect 矩形
rectangle(dst, rect, Scalar(0,255,255));
dst_img = src_img(rect);
}
}
if (rects.size() == 1) {
//如果rects集合中只有一个,直接获取即可
Rect rect = rects.at(0);
dst_img = src_img(rect);
}else {
//存在多个的情况
int lowPoint = 0;
Rect finalRect;
for (int i = 0; i < rects.size(); i++) {
Rect rect = rects.at(i);
Point p = rect.tl();
if (rect.tl().y > lowPoint) {
//循环检测y坐标最高的并获取
lowPoint = rect.tl().y;
finalRect = rect;
}
}
rectangle(dst, finalRect, Scalar(255, 255, 0));
//获取最终的Rect进行切割
dst_img = src_img(finalRect);
}
jobject bitmap = createBitmap(env,dst_img,config);
在jni层反射创建Bitmap
jobject createBitmap(JNIEnv *env, Mat srcData, jobject config) {
//通过jni反射创建Bitmap
int imgWidth = srcData.cols;
int imgHeight = srcData.rows;
int numPix = imgWidth * imgHeight;
jclass bmpCls = env->FindClass("android/graphics/Bitmap");
jmethodID createBitmapMid = env->GetStaticMethodID(bmpCls, "createBitmap",
"(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
jobject jBmpObj = env->CallStaticObjectMethod(bmpCls, createBitmapMid, imgWidth, imgHeight,
config);
Java_org_opencv_android_Utils_nMatToBitmap(env, 0, (jlong) &srcData, jBmpObj);
return jBmpObj;
}
8.tess-two
tess-two是Tesseract在Android平台上的移植。
主要功能是通过样本和图片进行比对,从而将图片转换成文字
样本的训练请参考https://blog.csdn.net/sylsjane/article/details/83751297
build.gradle配置
implementation 'com.rmtheis:tess-two:8.0.0'
new Thread(new Runnable() {
@Override
public void run() {
baseApi = new TessBaseAPI();
try {
InputStream is = null;
is = getAssets().open(language + ".traineddata");
File file = new File("/sdcard/tess/tessdata/" + language + ".traineddata");
if (!file.exists()) {
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
byte[] buffer = new byte[2048];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.close();
}
is.close();
//初始化TessBaseAPI
return baseApi.init("/sdcard/tess", language);
} catch (IOException e) {
e.printStackTrace();
}
}
});
//查找ID
public void searchId(View view) {
tesstext.setText(null);
ResultImage = null;
Bitmap bitmapResult = ImageProcess.getIdNumber(fullImage, Bitmap.Config.ARGB_8888);
fullImage.recycle();
ResultImage = bitmapResult;
//tesseract-ocr
idCard.setImageBitmap(bitmapResult);
}
//识别文字并显示
public void recognition(View view) {
// 识别Bitmap中的图片
baseApi.setImage(ResultImage);
tesstext.setText(baseApi.getUTF8Text());
baseApi.clear();
}