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

标签: opencv c++
13396人阅读 评论(5) 收藏 举报
分类:

        假设现有一些含身份证前景以及不确定背景的图像,想通过计算机将身份证区域检测出来,实现诸如用户拍照定位提示、背景分离等业务,用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分量;最后一张不是很完美):



查看评论

简单邮件传输协议SMTP封装类

简单邮件传输协议SMTP封装类作者:Asif Rasheed 翻译:刘建强 在Internet上,Email是最流行的传输媒体。这篇文章包括两个协议:. POP 3 协议: POP3协议(邮政传输协议...
  • ghj1976
  • ghj1976
  • 2001-08-22 18:15:00
  • 1423

基于opencv的身份证识别系统

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

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

如题,就是对身份证拍照,处理相应照片,识别出身份证号码 这里需要调用opencv库。opencv库包含了许多处理图像的函数,功能全面而且强大,兼容多种语言。如何配置可以自行搜索。  主要流程如下:...
  • seekerhit
  • seekerhit
  • 2016-01-20 11:53:26
  • 7092

利用opencv库识别身份证图片

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

身份证号码图像提取--基于canny边缘检测的连通域检测算法

使用openv canny边缘检测,进行连通域探测提取。
  • u200814342A
  • u200814342A
  • 2016-05-31 17:31:41
  • 4609

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

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

模式识别之身份证识别

在各种证件识别中,身份证识别相对来讲还是比较简单的,因为字体及位置固定,而且颜色与背景差别较大。 识别流程:                                             ...
  • what_lei
  • what_lei
  • 2015-10-14 21:53:21
  • 7660

FACE++ 进行身份证识别(自己上传身份证,本地识别)

FACE++ 进行身份证识别,自己上传身份证,本地识别,只是识别身份证上信息,区别于跳转到FACE++ 第三方平台验证。代码如下:private static final String APIKEY ...
  • u011619090
  • u011619090
  • 2018-03-09 09:33:05
  • 75

【OpenCV】基于图像处理和模式识别的火灾检测方法

学期末一直忙考试,大作业,很久没来CSDN耕耘了。。。 虽然考试都结束了,手头还是累积了不少活儿要补,不多写了,晒个小项目,之前一直做的,后来当做模式识别课程的大作业交了。 大体框架如下:...
  • qq_26093511
  • qq_26093511
  • 2016-05-07 09:47:21
  • 1481

**基于opencv库和tess-two在android平台上实现身份证号的识别!**

  • 2017年05月05日 14:02
  • 17.76MB
  • 下载
    最新评论