NDK OpenCV 身份证信息离线识别

news2025/7/19 17:37:02

 NDK系列之OpenCV 身份证信息离线识别技术实战,本节主要是通过OpenCV C++库,实现身份证信息识别,如身份证号码识别,本节使用到的技术点同样适用于车牌号识别、银行卡号码识别等。

实现效果:

 本节主要内容:

1.OpenCV库导入;

2.Java层代码实现;

3.Native层身份证识别;

4.OCR识别图片上面的文字。

源码:

NdkIdCard: NDK OpenCV 身份证信息离线识别

一、OpenCV库导入

1)复制OpenCV源文件到cpp目录下,动态库文件复制到jniLibs目录下:

2)在CMakeLists文件中,导入源文件和库文件

 二、Java层代码实现

MainActivity的从相册中选择身份证图片、查找身份证图片中的身份证号码区域、识别身份证号码区域的文字(身份证号码):

1)从手机相册中选择身份证图片,这个大家基本都会,不具体说明,最终获取到身份证图片的Bitmap对象赋值给fullImage变量;

public void search(View view) {
	if (!initPermission()) return;
	Intent intent;
	if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
		intent = new Intent();
		intent.setAction(Intent.ACTION_GET_CONTENT);
	} else {
		intent = new Intent(Intent.ACTION_PICK,
				MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
	}
	intent.setType("image/*");
	//使用选取器并自定义标题
	startActivityForResult(Intent.createChooser(intent, "选择待识别图片"), 100);
}

 2)查找身份证图片中的身份证号码区域

将Java层获取到的选择的身份证图片的Bitmap,即fullImage变量,传给Native层,通过OpenCV库,将身份证图片中的身份证号码区域找到,并裁剪出来;

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
	id.setImageBitmap(bitmapResult);
}

 ImageProcess.java:

public class ImageProcess {

    static {
        System.loadLibrary("native-lib");
    }

    public static native Bitmap getIdNumber(Bitmap src, Bitmap.Config config);
}

3)识别身份证号码区域的文字

将获取到的身份证号码区域图片,使用OCR识别成文字。

public void recognition(View view) {
	// 识别Bitmap中的图片
	baseApi.setImage(ResultImage);
	tesstext.setText(baseApi.getUTF8Text());
	baseApi.clear();
}

 三、Native层身份证识别

Native层工作主要是:获取Java层传递过来的身份证原图,使用OpenCV,找到身份证号码区域,裁剪该区域图片,并转化为Bitmap格式,返回Java层。

总体思路:

实现逻辑:

1)将Java层传递过来的bitmap转成的Mat,因为OpenCV支持的是Mat格式。

Mat src_img; // 身份证原图
Mat dst_img; // 身份证号码区域图
//将bitmap转换为Mat型格式数据
Java_org_opencv_android_Utils_nBitmapToMat2(env, type, src, (jlong) &src_img, 0);

2)无损压缩,压缩图片至640*400,减少后续查找身份证号码区域时间,提高效率。

#define DEFAULT_CARD_WIDTH 640
#define DEFAULT_CARD_HEIGHT 400
#define FIX_IDCARD_SIZE Size(DEFAULT_CARD_WIDTH,DEFAULT_CARD_HEIGHT)
resize(src_img, src_img, FIX_IDCARD_SIZE);

压缩后身份证图:

 3)灰度化,查找身份证号码区域跟图片颜色无关,将图片颜色值RBG 转化为 Gray,RBG: 256 *256 *256 = 2^24,Gray:256,转化后理论上效率提升提高2^16倍。转化公式:Gray f(i,j)=0.30R(i,j)+0.59G(i,j)+0.11B(i,j),这里直接使用OpenCV API即可:

cvtColor(src_img, dst, COLOR_BGR2GRAY);

灰度化后身份证图:

 4)二值化,再一步过滤,降噪;将图片颜色设置成只有黑白两种颜色,过滤掉灰色部分,如身份证背景波纹。

threshold(dst, dst, 100, 255, CV_THRESH_BINARY);

 二值化后身份证图:黑白色

5)膨胀,发酵,Native层目的是查找身份证号码区域,从身份证图中可以看出,身份证号码区域是一块有间隔连续的号码区域;我们是不是可以将像素点膨胀,使得身份证号码区域成为一块连续的号码区域;

Mat dst; // 膨胀身份证图
Mat erodeElement = getStructuringElement(MORPH_RECT, Size(20, 10));
erode(dst, dst, erodeElement);

 膨胀后身份证图:

6)轮廓检测,将连续像素点识别出来,并筛选出符合身份证号码区域的结果存放到集合中;身份证号码区域宽高比例 >  1:9,即width > height * 9的加入集合。

vector<vector<Point> > contours;
vector<Rect> rects;
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));
	//rectangle(dst, rect, Scalar(0, 0, 255));  // 在dst 图片上显示 rect 矩形
	if (rect.width > rect.height * 9) {
		rects.push_back(rect);
		rectangle(dst, rect, Scalar(0, 255, 255));
		dst_img = src_img(rect);
	}
}

 轮廓检测后的身份证图:

 7)如果筛选后集合中只有1条数据,那么该数据将是身份证号码区域;否则遍历集合,取区域y坐标值最大的区域为身份证号码区域,因为身份证号码区域在身份证图中位于最底部。
注:真实场景可能存在身份证原图旋转,或者倒着等不规范的图片,我们要在拍照的时候提示用户将身份证放到识别框中拍照,尽可能从上层避免上面所说的不规范图片。

if (rects.size() == 1) {
	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) {
			lowPoint = rect.tl().y;
			finalRect = rect;
		}
	}
	rectangle(dst, finalRect, Scalar(255, 255, 0));
	dst_img = src_img(finalRect);
}

身份证识别框拍照:

8)将裁剪的身份证号码图dst_img(Mat格式)转化为bitmap格式,返回java层

jobject bitmap = createBitmap(env, dst_img, config);

src_img.release();
dst_img.release();
dst.release();

return bitmap;

裁剪的身份证号码图 :

四、OCR识别图片上面的文字

1)依赖OCR 库 tess-two

implementation 'com.rmtheis:tess-two:7.0.0'

2)导入身份证号码识别训练学习的样本,训练学习的样本越多,OCR识别到的身份证号码越准确。

身份证号码识别训练学习的样本是一个二进制文件:cn.traineddata,这里可以直接使用我源码里面的身份证号码识别训练学习的样本。区别于收费的OCR识别公司,只要在于训练学习的样本数量,个人开发者很难做到使用大量的样本数完成训练学习工作;所以由于我的训练学样本很少,会存在一些号码数字识别不准确,如6可能识别到的是4等。

 3)初始化tess-two库

private TessBaseAPI baseApi;
private void initTess() {
	new AsyncTask<Void, Void, Boolean>() {
		@Override
		protected void onPreExecute() {
			showProgress();
		}

		@Override
		protected void onPostExecute(Boolean result) {
			dismissProgress();
			if (!result) {
				Toast.makeText(MainActivity.this, "load trainedData failed", Toast.LENGTH_SHORT).show();
			}
		}

		@RequiresApi(api = Build.VERSION_CODES.N)
		@Override
		protected Boolean doInBackground(Void... params) {
			baseApi = new TessBaseAPI();
			try {
				InputStream is = null;
				is = getAssets().open(language + ".traineddata");
				String path = mContext.getDataDir().getAbsolutePath();
				LogUtil.i(TAG, "initTess path " + path);
				File file = new File(path + "/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();
				return baseApi.init(path, language);
			} catch (IOException e) {
				e.printStackTrace();
				LogUtil.i(TAG, "initTess err " + e.getMessage());
			}
			return false;
		}
	}.execute();
}

4)调用API识别身份证号码区域的文字

public void recognition(View view) {
	// 识别Bitmap中的图片
	baseApi.setImage(ResultImage);
	tesstext.setText(baseApi.getUTF8Text());
	baseApi.clear();
}

至此,OpenCV 身份证信息离线识别技术项目已完成;车牌号识别、银行卡号码识别等也是同样的实现思想。

源码:

NdkIdCard: NDK OpenCV 身份证信息离线识别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/444071.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库底层运行原理之——事务管理器

一般所有关系型数据库内部都有自己的事务机制&#xff0c;进程是如何保证每个查询在自己的事务内执行的&#xff0c;通过这篇文章来简单介绍一下。 我们可以理解为数据库是由多种相互交互的组件构成的&#xff0c;数据库一般可以用如下图形来理解&#xff1a; 事务管理器就是今…

两种方法,计算带地形起伏的地表面积

很多同学会经常计算占地面积, 就会用到投影面积计算和椭球体面积计算; 还有一些,需要去计算表面积, 也就是带地形起伏的地表面积, 这......咋办呢? 我们来介绍两种方法, 计算下面这个区域的地表面积—— 两种方法各有优势, 大家各取所需 方法一:表面体积工具 这…

【hello Linux】进程优先级

目录 1. 基本概念 2. 查看系统进程&#xff1a;&#xff08;包括优先级&#xff09; 2.1 使用命令查看系统进程 2.2 各字段分析 2.3 优先级的修正解释 2.4 使用 top 命令修改优先级 其他概念 Linux&#x1f337; 1. 基本概念 进程的优先权&#xff08; priority&#xff09;&…

Java版企业电子招投标系统源代码之电子招投标系统建设的重点和未来趋势

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及…

网工神器:PNETLab模拟器踩坑过程(一)

0、前言 由于工作需要&#xff0c;想测试一下SD-WAN&#xff0c;手边既没有测试环境又没有测试设备。突然想到为什么不用模拟器测试。经过我一番操作好像发现了新大陆&#xff0c;没想到模拟器的世界发生了翻天覆地的变化。真是“一日学习一日功&#xff0c;一日不学十日空”。…

【IoT】以一款实际产品为例,来谈谈如何做商业计划分析

本篇内容以笔者早期刚转型做产品时,实际负责的一款产品为例,来谈谈如何做产品的商业计划分析。 首先简单介绍一下这款产品: 这是一款电子便签产品,目的是为了替换纸质便签,增加一些智能化的提醒控制。 该产品通过蓝牙与手机端连接,应用端配置好提醒信息后一键同步至产…

鼠标悬停发光按钮,流转边框

提示&#xff1a;css 动画实现&#xff0c;鼠标悬停发光按钮&#xff0c;流转边框。鼠标border可以旋转 前言 提示&#xff1a;以下是本篇文章的代码内容,供大家参考,相互学习 一、html代码 <!DOCTYPE html> <html><head><meta http-equiv"content…

企业信息化建设该怎么做?方向和手段都在这了

企业信息化建设该怎么做&#xff1f; 如果现在是十年前&#xff0c;我一定会说&#xff0c;做信息化需要寻找熟悉不同编程语言、有经验的程序员。 但是现在&#xff0c;如果不是特别复杂的信息化系统&#xff0c;其实公司完全可以使用零代码平台自主开发&#xff0c;不需要再…

[计算机图形学]光线追踪:加速结构(前瞻预习/复习回顾)

一、前言 上篇我们提到了&#xff0c;如果在光线追踪中&#xff0c;我们真的用每个像素发出的光线&#xff0c;以及在场景中弹射之后的光线与场景中的许多模型的上千万个三角形求交那将是一个非常慢的计算过程&#xff0c;所以&#xff0c;本篇我们将介绍一些加速结构来加速这个…

【FTP服务】

目录 一、FTP服务二、FTP服务器安装配置FTP服务的安装匿名访问开启防火墙设置本地用户修改配置文件 以图形化的格式来写入文件 三、设置白名单&#xff0c;黑名单用户 一、FTP服务 作用: 是用来传输文件的协议 端口: FTP服务器默认使用TCP协议的20、21端口与客户端进行通信 2…

OpenHarmony生态贡献获肯定,华秋践行加速硬件创业初心

4月19日,以“开源正当时,共赢新未来”为主题的开放原子开源基金会OpenHarmony开发者大会2023(以下简称“大会”)成功举办。大会现场,来自开放原子开源基金会和OpenHarmony项目的领导与专家、以及共建单位、行业伙伴和社区开发者们共聚一堂。值得信赖的电子产业一站式服务平台华…

【软件测试】四面成功上岸美团

最后&#xff0c;总结一下个人认为比较重要的知识点&#xff1a;接口自动化测试 &#xff1a;测试框架&#xff0c;多个有关联的接口的用例编写&#xff0c;用例的组织及存储&#xff0c;接口测试的覆盖率&#xff0c;RESTAssured 的封装等。UI 自动化测试 &#xff1a;iOS 和 …

二维码+互联网云技术在中建二局施工项目管理中的应用实践

中建二局&#xff08;全称&#xff1a;中国建筑第二工程局有限公司&#xff09;是世界500强企业—中国建筑股份有限公司的全资子公司&#xff0c;是集房建、基建、核电、火电、风电等多种建设和投资相融合的、国内最具综合实力的大型国有企业集团公司。中建二局具有土木建筑、设…

Jetson Orin Nano下部署 Yolo v5

在网上找了好多关于Jetson Nano部署Yolo v5的帖子&#xff0c;由于每个人的环境和版本都不同&#xff0c;过程也都有所不同&#xff0c;因此在Jetson Orin Nano CLB上安装Yolo v5也有必要记录一下过程&#xff0c;以便后续无脑重装&#xff0c;让我们开始。 由于我这个Jetson …

【IT成神路之我在起点学网络~】

什么是网络&#xff0c;一开始我以为是能刷刷剧&#xff0c;让我看到心仪idol&#xff0c;坐在家中看祖国大好河山就是网络。 长时间浸泡在网络上&#xff0c;不得不让我思索我为什么能看到高清不卡顿的精彩视频。 于是乎……我开始大肆搜索网络的资料内容。 IT嘛&#xff0…

OCR技术大揭秘:纸质文档数字化的新选择

引言 OCR&#xff08;Optical Character Recognition&#xff09;即光学字符识别技术&#xff0c;是一种将纸质或电子文档中的印刷文字转化为可编辑和可搜索的数字文本的技术。随着数字化和信息化的快速发展&#xff0c;OCR 技术逐渐成为处理大量纸质或电子文档的主要手段之一…

【Zblog建站】搭建属于自己的博客网站,并内网穿透实现公网访问

文章目录 1. 前言2. Z-blog网站搭建2.1 XAMPP环境设置2.2 Z-blog安装2.3 Z-blog网页测试2.4 Cpolar安装和注册 3. 本地网页发布3.1. Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 想要成为一个合格的技术宅或程序员&#xff0c;自己搭建网站制作网页是绕…

基于Java+Springboot+vue网上商品订单转手系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

机器学习(一)K近邻算法(KNN)原理剖析及python源码

本篇介绍第一个机器学习算法&#xff1a;k-近邻算法&#xff0c;它非常有效而且易于掌握。首先&#xff0c;我们将探讨k-近邻算法&#xff08;KNN&#xff09;的基本理论&#xff0c;以及如何使用距离测量的方法分类物品&#xff1b;其次我们将使用Python从文本文件中导入并解析…

【C++】你知道为什么在写C++代码之前要在开头写上using namespace std吗?

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…