相信很多人手机里都装了个“扫描全能王”APP,平时可以用它来可以扫描一些证件、文本,确实很好用,第一次用的时候确实感觉功能很强大啊算法很牛逼啊。但是仔细一想,其实这些实现起来也是很简单的,我想了下,实现的步骤应该就只有下面三个:
将证件轮廓找到
提取证件矩形轮廓四点进行透视变换
二值化
知道原理之后,我马上利用强大的opencv开发一个类似“全能扫描王”扫描工具。
整理一下我们要制作的这个扫描工具有哪些功能:
图像的信息区域的提取与矫正
图像的二值化
锐化和增强
第二第三点都非常简单,那么制作这个工具的难点完全落在了第一点“ 图像的信息区域的提取与矫正”上了。在编码实现的过程中,确实有很多坑需要踩一踩。
我们先展示一下效果,我们有这么一个用手机拍摄的图片
经过扫描工具一番处理后变成这样子。也就是说,我们将原图中的那个文件抠了了出来,并且完成矫正。
实现过程查阅了大量资料,也看了网上很多类似的博客,前辈们实现过相类似的透视变换的代码,但是他们的代码实现的都不理想,很多图片根本没法检测。不过还是可以从前人的经验中获取到很多好想法的,所以先列出一些有借鉴的博客:
正式实现
第一步,二值化+高斯滤波+膨胀+canny边缘提取
一开始我是没有采取形态学处理的,仅仅是二值化+高斯滤波+canny边缘提取的策略,但是实际运行下效果并不好,原因在于有一些图片的信息区域轮廓没法闭合,这就导致了信息区域轮廓没法提取。但是加入适当的膨胀后,效果就好多了。
Mat src = imread("1.png");
imshow("src img", src);
Mat source = src.clone();
Mat bkup = src.clone();
Mat img = src.clone();
cvtColor(img, img, CV_RGB2GRAY); //二值化
imshow("gray", img);
//equalizeHist(img, img);
//imshow("equal", img);
GaussianBlur(img, img, Size(5, 5), 0, 0); //高斯滤波
//获取自定义核
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3)); //第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的
//膨胀操作
dilate(img, img, element); //实现过程中发现,适当的膨胀很重要
imshow("dilate", img);
Canny(img, img, 30, 120, 3); //边缘提取
imshow("get contour", img);
}
轮廓提取效果如下: