2021SC@SDUSC
android studio版本 4.1.2
sdk版本 Compile SDK version:30
Build Tools Version 30.0.3
gradle版本 6.8.3
OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
发现在OpenCV官网下载的安装包适用于Linux/Mac,因此需要使用CMake工具来进行编译安装,但是只适配于xcode6版本,所以采用homebrew来安装
命令:brew install opencv
为项目配置openCV:
这两个函数,以便opencv能正确启动
if (!OpenCVLoader.initDebug()) {
Log.d("OpenCV", "Internal OpenCV library not found. Using OpenCV Manager for initialization");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
} else {
Log.d("OpenCV", "OpenCV library found inside package. Using it!");
//OpenCV库加载并初始化成功后的回调函数
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}
}
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i("OpenCV", "OpenCV loaded successfully");
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
开发人员的算法思路是,对于发生畸变的图:
1.采⽤寻找轮廓的⽅法,⽤approxPolyDP函数,对图像轮廓点进⾏多边形拟合
2.把图像的四个顶点处的点归类,划分出四个区域{左上,右上,右下,左下},利⽤opencv的寻找轮廓,得到最⼤轮廓,然后⽣成最⼩外接矩形,确定四个顶点的⼤致位置。设置⼀个阀值,与上图中的点集合求距离,⼤于阀值的舍弃,⼩于的保留。
3.所有的点集都落到了四个区域,利⽤矩形中,对⻆线距离最⼤,确定四个顶点的位置
4.根据输⼊和输出点获得图像透视变换的矩阵
5.透视变换。透视变换(Perspective Transformation)是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换。
利用canny算法进行边缘检测:
代码:
/**
* canny算法,边缘检测
*
* @param src
* @return
*/
public static Mat canny(Mat src) {
Mat mat = src.clone();
Imgproc.Canny(src, mat, 60, 200);
return mat; }
Mat类 (Matrix的缩写) 是OpenCV用于处理图像而引入的一个封装类。
Mat类可以分为两个部分:矩阵头和指向像素数据的矩阵指针。矩阵头 包括数字图像的矩阵尺寸、存储方法、存储地址和引用次数等,矩阵头的大小是一个常数,不会随着图像的大小而改变,但是保存图像像素数据的矩阵则会随着图像的大小而改变,OpenCV使用了引用次数,当进行图像复制和传递时,不再复制整个Mat数据,而只是复制矩阵头和指向像素矩阵的指针,并且修改引用次数。
这里可以明白,Mat实际上就是一个描述且指向图像像素数据的图像说明类,为什么这里使用src的clone()方法,而不使用赋值或者copy?
这就和我们上学期的课程,oop的浅拷贝、深拷贝相关。正如上面所说,Mat中有一个指向像素数据的的矩阵指针
Canny参数解释
src:输入图像
mask:输出掩码
lowThresh:低阈值
ratio*lowThresh:高阈值
kernel_size:卷积核大小:奇数
*/
//Canny输出结果为掩码
Canny是双阈值筛选。通过非极大值抑制后,仍然有很多的可能边缘点,进一步的设置一个双阈值,即低阈值(low),高阈值(high)。灰度变化大于high的,设置为强边缘像素,低于low的,剔除。在low和high之间的设置为弱边缘。进一步判断,如果其领域内有强边缘像素,保留,如果没有,剔除。这样做的目的是只保留强边缘轮廓的话,有些边缘可能不闭合,需要从满足low和high之间的点进行补充,使得边缘尽可能的闭合,从而得到闭合图像
这样,mat中就保存了边缘检测后的图像输出
代码:
/**
* 利⽤函数approxPolyDP来对指定的点集进⾏逼近
*
* @param cannyMat
*/
public static Point[] useApproxPolyDPFindPoints(Mat cannyMat) {
List contours = new ArrayList();
MatOfPoint:2D点对象,通过x,y来确定点的位置
Mat hierarchy = new Mat();
// 寻找轮廓
Imgproc.findContours(cannyMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE,
new Point(0, 0));
// 找出匹配到的最大轮廓
Imgproc模块包含了一系列常用的图形处理算法,可以使用Imgproc直接调用这些方法,包含了:
线性滤波
形态学处理
Image Pyramids
Thresholding Operations
边缘检测
检测直线
仿射变换
findContours函数参数解析如下:
findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point());
InputOutputArray image:单通道图像矩阵,常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;
OutputArrayOfArrays contours:定义为vector
有多少轮廓,向量contours就有多少元素。
OutputArray hierarchy:vector
Vec
int mode:定义轮廓的检索模式,有以下取值:
CV_RETR_EXTERNAL:只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
CV_RETR_LIST :检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,即这个检索模式下不存在父轮廓或内嵌轮廓, 所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1
CV_RETR_CCOMP :检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层
CV_RETR_TREE:检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
int method:定义轮廓的近似方法,有以下取值:
CV_CHAIN_APPROX_NONE: 保存物体边界上所有连续的轮廓点到contours向量内
CV_CHAIN_APPROX_SIMPLE :仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours,拐点与拐点之间直线段上的信息点不予保留
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain近似算法
Point offset=Point()偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,Point可以是负值。
开发人员使用到了:
Imgproc.findContours(cannyMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE,
new Point(0, 0));
就是对cannyMat(我们之前得到的对图像进行边缘检测后得到的二值图像)进行轮廓寻找,寻找到符合的轮廓输出到contours中,第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号存储在hierarchy中;
轮廓的检索模式选择只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略,我们可以通过最外围轮廓来调整图像,简化工作量;
轮廓的近似方法选择CV_CHAIN_APPROX_NONE,保存物体边界上所有连续的轮廓点到contours向量内;
轮廓的偏移量设置为(0,0),不改变
开始学习openCV相关内容,了解了canny算法,本篇分析了canny边缘检测的代码和寻找最大轮廓的部分代码,对openCV有了一定的了解,在接下来的时间坚持深入学习,下一篇将分析寻找最大轮廓的剩余代码并去获取四个顶点的参照点