由于新公司的项目需要使用openCV进行图像扫描,将图片中的文档位置扫描出来,并经过矩阵变换为矩形,网上查阅了一些资料后,发现使用openCV是一个不错的选择,因此到网上找了一些资料来学习,由于openCV是一个非常庞大的库,我这里只选择了项目需要的一些方法,其他的有空的时候会去学习。
我们先大致了解下openCV:openCV是一个图形处理库,囊括了大量的图形处理函数。
一、openCV在iOS上的使用:
在openCV官网可以找到openCV官网上iOS的framework的下载链接;我下载的是这个版本的:

下载了opencv2.framework后,加入到工程中,然后直接在调用的地方加上头文件就行了;这里有个需要注意的地方,网上其他的教程基本上都是导入的比较老的framework的sdk了,在3.2版本的sdk中我们需要导入的头文件是#import <opencv2/imgcodecs/ios.h>和<opencv2/opencv.hpp>
二、openCV的基础知识:Mat
Mat是openCV中表示图片的类,由两个数据结构组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。关于Mat类,首先我们需要知道的是:
1、我们不必为其手动开辟空间;
2、不必在不需要的时候立即释放其使用的空间;
3、指针指向的矩阵占用的空间开销要远大于头部信息的开销。
为了解决大图的复制导致内存占用过多的问题,openCV使用了引用计数的机制,不是必须的情况下,让每个Mat对象都有自己的信息头,但是共享同一个矩阵。如下:
Mat A,C;//此时仅创建了信息头部部分;
A = imread(“1.jpg”); //这里才会为矩阵开辟内存空间;
Mat B(A); // 使用拷贝构造函数,但是此时复制的仅仅只是信息头部部分,指针信息都指向同一个地址块;
注:当某些必要的时候,我们可能需要开辟新的空间来存储新的图像,这个时候可以使用clone或者copyTo函数来复制整个图像(信息头和矩阵指针);
三、需求分析
具体的需求可以通过知乎上的一个问题引出,如下图:

思路也跟上面链接差不多,大步骤就是两个:取点和矩阵修正;
1、图片预处理:灰度处理和使用Mean Shift进行降噪处理,Mean Shift的有点在于如果是像背景桌面的浅色纹理,图像分割的过程中相当于将这些小的浮动过滤掉,并且保留相对明显的纸张边缘。(优化部分,图片过大的时候,可以先将图片缩小之后再降噪)
2、边缘检测:可以使用canny算法得到图片的边缘线;
3、直线检测:使用HoughLinesP函数获取图片中所有的直线;
4、求出多边形:此处求出多边形的算法比较粗糙,就是找到步骤3中所有直线里面最左边,最右边,最上边和最下边的四条,然后找到他们的四个交点就可以取出一个矩形了。
5、透视转换:得到的图形一般不是我们需要的长方形,因此需要进行透视转换,将所得到的图片转换成我们需要的长方形图片;可以直接使用openCV的getPerspectiveTransform计算转化矩阵,再用warpPerspective调用转化矩阵进行拉伸。
这里有一个大坑的地方就是,所有网上的资料都是直接使用UIImageToMat方法将UIImage和Mat进行转换的,这样是不行的,因此直接用iPhone拍的照片会在转化的过程中顺时针转动90度,所以我们需要将原图如下处理后才可以得到正着的图片:
//图片修正
UIImage* correctImage = image;
UIGraphicsBeginImageContext(correctImage.size);
[correctImage drawInRect:CGRectMake(0, 0, correctImage.size.width, correctImage.size.height)];
correctImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
cv::Mat img;
UIImageToMat(correctImage, img);
这个还是在一个日本佬的博客上上看到的,国人的博客和英文网站纯属瞎扯淡,另外如果使用cv::imread函数去读取照片,照片也会变色,这个我就没有多研究了,有兴趣的同学可以自行查下资料,看是哪里出的问题。
这样之后得到的图片就会成为一个比较好看的图片了。这个完成了之后,需求算是完成了一半,后面还需要自定义相机和对图片拉伸处理。
最后,在整理好代码后,我会将代码放到github上。
网友评论