概述: 本节主要结合降噪,色域转换,二值化,边缘检测及获取轮廓等函数,实现对身份证的边缘位置检测;
完整Demo 传送门
一: 本节目的:
先展示一下效果:
本人真实身份证(留个眼睛看着你们...),听说最近有一键卸妆的软件,唉,你要真给我卸了也就认命了;不扯淡,说正题,这个效果有什么用呢?
说实话我也不知道,恰好最近有这么个需求而已,要求如下:
检测身份证,银行卡,营业执照等等....要在UI上提示用户拍摄时目标证件是否在要求的框框范围之内,不能超出也不能太小,嗯,没毛病,就是这样的;
二.实现过程:
三. 代码实现:
#import
...
...
using namespace cv;
using namespace std;
double minThreshold = 10;
double ratioThreshold = 3;
- (void)viewDidLoad{
[super viewDidLoad];
Mat sourceMatImage;
UIImageToMat(self.imageView.image, sourceMatImage);
// 降噪
blur(sourceMatImage, sourceMatImage, cv::Size(3,3));
// 转为灰度图
cvtColor(sourceMatImage, sourceMatImage, CV_BGR2GRAY);
// 二值化
threshold(sourceMatImage, sourceMatImage, 190, 255, CV_THRESH_BINARY);
// 检测边界
Canny(sourceMatImage, sourceMatImage, minThreshold * ratioThreshold, minThreshold);
// 获取轮廓
std::vector> contours;
findContours(sourceMatImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
/*
* 重新绘制轮廓
*/
// 初始化一个8UC3的纯黑图像
Mat dstImg(sourceMatImage.size(), CV_8UC3, Scalar::all(0));
// 用于存放轮廓折线点集
std::vector> contours_poly(contours.size());
// STL遍历
std::vector>::const_iterator itContours = contours.begin();
std::vector>::const_iterator itContourEnd = contours.end();
// ++i 比 i++ 少一次内存写入,性能更高
for (int i=0 ; itContours != itContourEnd; ++itContours,++i) {
approxPolyDP(Mat(contours[i]), contours_poly[i], 15, true);
// 绘制处理后的轮廓,可以一段一段绘制,也可以一次性绘制
// drawContours(dstImg, contours_poly, i, Scalar(208, 19, 29), 8, 8);
}
/*如果C++ 基础不够,可以使用 for 循环
* for (int i = 0; i < contours.size(); i ++) {
* approxPolyDP(contours[i] , contours_poly[i], 5, YES);
* }
*/
// 绘制处理后的轮廓,一次性绘制
drawContours(dstImg, contours_poly, -1, Scalar(208, 19, 29), 8, 8);
// 显示绘制结果
self.desImageView.image = MatToUIImage(dstImg);
补充:截取的边界应该去除透视投影:
CV_EXPORTS Mat getPerspectiveTransform( const Point2f src[], const Point2f dst[] );
CV_EXPORTS_W void warpPerspective( InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags=INTER_LINEAR,
int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar()
);