关闭

【OpenCV3.3】检测图像中的身份证区域

标签: opencvc++
12249人阅读 评论(2) 收藏 举报
分类:

        假设现有一些含身份证前景以及不确定背景的图像,想通过计算机将身份证区域检测出来,实现诸如用户拍照定位提示、背景分离等业务,用OpenCV该如何做呢?如果输入图像前景和背景同时具有一定区分度,并且没有光照污染(即均匀光照),那么本文介绍的方法似乎是一种较快的检测方案(因为对输入图像要求比较严格, 故计算量少)。

        首先我们来看看一些例子(来自互联网):


        可以看到,这些图像都有一些共同点,就是干净(几乎没有噪声)、清晰(前后背景区分度大)。我们按照如下几个步骤来一步步实现检测身份证区域:

  1. 灰度化。同其它图像检测预处理步骤一样,这一步目的在于将图像转为单通道灰度图,通过丢掉一些影响不大的颜色信息来加快计算。OpenCV提供了几种转灰度图的方法,一个是在读取时(cv::imread、cv::imdecode)指定cv::IMREAD_GRAYSCALE,另一个是颜色空间转换(cv::cvtColor)指定cv::COLOR_BGR2GRAY,还有就是cv::split等。考虑到身份证的颜色特征,我们使用分量法,即提取原图的B分量作为灰度图(在本例中B相比G、R分量得到的结果前后背景区分度会大一些)。
    cv::Mat mvs[3];
    cv::split(image_color, mvs);
    
    cv::Mat &r = mvs[0]; // roi
  2. 二值化。OpenCV支持全局阀值(cv::threshold)和自适应阀值(cv::adaptiveThreshold),前面说了本文的方法会比较快,部分原因就是这里使用全局阀值而不是自适应阀值。关于全局阀值,OpenCV提供了两种确定算法,最大类间方差法cv::THRESH_OTSU和三角形算法cv::THRESH_TRIANGLE,我们这里使用了简化版的OTSU:在计算图像直方图时不对整幅图像进行计算,而是仅仅提取图像上下左右和中间五个小区域进行计算。
    // 计算指定区域直方图峰值所在的范围
    static int calcDistrib_Rel(const cv::Mat &image_gray, const cv::Rect &roi)
    {
    	int maxv = 0;
    	int histogram[UCHAR_MAX + 1] = { 0 };
    
    	// TODO: loop unrolling & optimization
    	const size_t image_step       = image_gray.step;
    	const uchar *__restrict pdata = image_gray.data + roi.y * image_step;
    	const int_fast32_t y_upper    = roi.y + roi.height;
    	const int_fast32_t x_upper    = roi.x + roi.width;
    	for (int_fast32_t i = roi.y; i < y_upper; ++i) {
    		auto pline_data = pdata + roi.x;
    		for (int_fast32_t j = roi.x; j < x_upper; ++j) {
    			int_fast32_t m  = *pline_data++;
    			int_fast32_t v  = ++histogram[m];
    			if (v > histogram[maxv]) maxv = m;
    		}
    		pdata += image_step;
    	}
    
    	int mid = histogram[maxv] / 2;
    	int low = maxv, high = maxv;
    	while (low > 0 && histogram[--low] >= mid) {
    	}
    	while (high < UCHAR_MAX && histogram[++high] >= mid) {
    	}
    
    	return MAKELONG(low, high);
    }
    
    // 假设身份证位于图像中部
    // 通过直方图计算上下左右和中间块区域的颜色区分度
    static constexpr int block_scale = 10;
    int block_width  = r.cols / block_scale;
    int block_height = r.rows / block_scale;
    int e = calcDistrib_Rel(r, cv::Rect((r.cols - block_width) / 2 - 1, (r.rows - block_height) / 2 - 1, block_width, block_height));
    int a = calcDistrib_Rel(r, cv::Rect(0, 0, block_width, block_height));
    int m = HIWORD(a) <= LOWORD(e), n = LOWORD(a) >= HIWORD(e); // 背景颜色分布在前景前、后还是有重叠,从直方图很容易看出来
    int b = m || n ? calcDistrib_Rel(r, cv::Rect(r.cols - block_width - 1, 0, block_width, block_height)) : a;
    int o = (m && HIWORD(b) <= LOWORD(e)) || (n && LOWORD(b) >= HIWORD(e));
    int c = !o ? b : calcDistrib_Rel(r, cv::Rect(0, r.rows - block_height - 1, block_width, block_height));
    int q = (m && HIWORD(c) <= LOWORD(e)) || (n && LOWORD(c) >= HIWORD(e));
    int d = !q ? c : calcDistrib_Rel(r, cv::Rect(r.cols - block_width - 1, r.rows - block_height - 1, block_width, block_height));
    int s = (m && HIWORD(d) <= LOWORD(e)) || (n && LOWORD(d) >= HIWORD(e));
    // 上述m、n、o、q、s都是区域颜色是否重叠的标志,之所以这样做是为了快速判断输入图像能否使用当前方案,避免多余计算
    
    if (s) {
    	int threshold = m ?
    		Utility::select_max(HIWORD(a), HIWORD(b), HIWORD(c), HIWORD(d)) :
    		Utility::select_min(LOWORD(a), LOWORD(b), LOWORD(c), LOWORD(d));
    	threshold = m ?
    		threshold + (LOWORD(e) - threshold) * 0.45 :
    		HIWORD(e) + (threshold - HIWORD(e)) * 0.60; // 让阀值尽可能靠近背景
    	cv::Mat r_threshold;
    	cv::threshold(r, r_threshold, threshold, UCHAR_MAX, m ? cv::THRESH_BINARY : cv::THRESH_BINARY_INV);
    } else {
    	// 这里表明前、背景有颜色重叠,可能是背景颜色和身份证近似,或者光照污染,此时全局阀值二值化的结果肯定不好,会丢失轮廓,可以考虑自适应阀值+形态学滤波cv::MORPH_GRADIENT等来得到轮廓明显的图像,这里就不贴了。
    }
    
  3. 轮廓提取。通过上述二值化处理之后身份证轮廓已经比较清晰了,所以省去调用各种算子(如Canny、Sobel等)进行边缘检测的步骤,直接进行轮廓信息提取。
    std::vector< std::vector<cv::Point> > contours_list;
    std::vector<cv::Vec4i> hierarchy;
    // Since opencv 3.2 source image is not modified by this function
    cv::findContours(r_threshold, contours_list, hierarchy,
    		 cv::RetrievalModes::RETR_EXTERNAL, cv::ContourApproximationModes::CHAIN_APPROX_NONE);
    
  4. 把结果画回原图看看。
    for (auto &contour : contours_list) {
    	cv::Rect &&rect = cv::boundingRect(contour);
    	if (rect.width > (r.cols / 2) && rect.height > (r.rows / 2)) {
    		//cv::rectangle(image_color, rect, cv::Scalar(0, 255, 0), 5);
    		std::vector<cv::Point2f> poly;
    		cv::approxPolyDP(contour, poly, 2, true);
    		for (uint32_t i = 0; i < poly.size() - 1; ++i) {
    			cv::line(image_color, poly[i], poly[i + 1], cv::Scalar(0, 255, 0), 6);
    		} //for
    		cv::line(image_color, poly[poly.size() - 1], poly[0], cv::Scalar(0, 255, 0), 6);
    		break;
    	} //if
    }

        效果截图(里面的r是ROI不是r分量;最后一张不是很完美):



0
0
查看评论

基于opencv的身份证识别系统

一、前言 本文主要实现了对身份证图片上身份证号码的自动识别,在Qt平台上使用opencv进行图像处理,并绘制简单的用户界面,设计了一个基于Qt和opencv的身份证号码识别系统。 二、用户界面        用户界面如下所示,简单几个控件,这里只是实现了身份...
  • AP1005834
  • AP1005834
  • 2016-05-24 22:04
  • 11125

调用opencv库进行身份证号码识别主要流程

如题,就是对身份证拍照,处理相应照片,识别出身份证号码 这里需要调用opencv库。opencv库包含了许多处理图像的函数,功能全面而且强大,兼容多种语言。如何配置可以自行搜索。  主要流程如下: 读取照片,转化为灰度图像; 设置阈值,将灰度图像转化为2值图像(即黑白图); 将图...
  • seekerhit
  • seekerhit
  • 2016-01-20 11:53
  • 6609

Opencv+C++之身份证识别(一)

五月份各种课程,也是最后一个学期了,所以就没有跟大家分享自己的一些所学。现在课程终于结束了,即将开始下一阶段的项目开发,所以趁这个间隙把前段时间做的一些东西做一个总结吧。 言归正传,对各种证件的识别系统大家都不陌生,尤其是对车牌号的识别已经应用到我们生活的很多方面,例如小区摄像头对入库车辆车牌的识...
  • dddxxxx
  • dddxxxx
  • 2016-07-22 10:08
  • 3106

利用opencv库识别身份证图片

一、前言 本文主要实现了对身份证图片上身份证号码的自动识别,在Qt平台上使用opencv进行图像处理,并绘制简单的用户界面,设计了一个基于Qt和opencv的身份证号码识别系统。 二、用户界面        用户界面如下所示,简单几个...
  • huobanjishijian
  • huobanjishijian
  • 2017-05-24 17:06
  • 2146

基于Qt和opencv的身份证号码识别系统

  • 2016-05-24 22:13
  • 2.76MB
  • 下载

使用谷歌开源组件tesseract-OCR识别身份证,通过opencv处理图像后再进行识别(windows版本)

1,前面有一篇已经介绍tesseract-OCR的简单实用和识别,因识别率不高,特意将图片实用opencv处理后,再次进行识别,经过测试,识别率高了30%左右 2,实用opcv整合tesseract-OCR需要的jar包,此处的识别已经不再通过调用windows系统命令,而通过tesseract-...
  • xingfeichen
  • xingfeichen
  • 2017-04-10 11:14
  • 5503

iOS 使用OpenCV和TesseractOCR识别身份证号码

  • 2017-11-29 16:59
  • 24.78MB
  • 下载

银行卡号识别Bank Card Rec 主要功能接口说明

Bank Card Rec 主要功能接口说明: 说明:如果需要其他接口都可以封装出来 主接口 /*调用识别之前先初始化一次*/ int init_all (); /* 调用识别,读取图像版本函数: picture_file-输入图像名字,支持bmp、jpg、png、tif等等; s_result...
  • zhubenfulovepoem
  • zhubenfulovepoem
  • 2017-11-21 19:53
  • 324

机器视觉学习系列四:身份证识别

项目背景:基于手机平台,识别身份证编号、姓名、年龄、地址,性别等; 具体实施方案: 1、基于身份证分类器检测身份证的位置,关于身份证分类器,采用的是HAAR+adaboost算法进行训练; 2、在已经检测到的候选身份证区域里,进行垂直边缘检测; 3、形态学运行,连接垂直边缘; 3、去除干扰连通区域,...
  • opencv123456
  • opencv123456
  • 2015-06-27 23:45
  • 8781

基于二代身份证的人脸对比系统

基于二代身份的人脸对比系统 基于二代身份证的人脸对比系统可以划分为如下三个部分。分别为人脸检测、人脸特征点提取、以及特征点的匹配和相似度计算。根据相似度的大小确定是同一个人的可能性大小,设定一个大阈值bigthreshold、一个小阈值smallthreshold,大于bigthreshold则判定...
  • baolinq
  • baolinq
  • 2017-08-13 10:27
  • 1436
    联系作者
    通过QQ与我联系(全天候7*24小时基本不在线)
    最新评论
    免责声明
    如果转载的文章侵犯了您的版权,请务必告知,我将立刻删除;
    博客所有文章允许转载,原创类不要求注明出处,随意就好;
    如果是转载的文章,建议直接转载原始来源,因为原作者极可能有更新