1 #include<opencv2/core/core.hpp>
2 #include<opencv2/highgui/highgui.hpp>
3 #include<opencv2/imgproc/imgproc.hpp>
4 #include<opencv2/objdetect.hpp>
5 #include<iostream>
6
7 using namespace std;
8 using namespace cv;
9
10 int main(int argc, char **argv) {
11 //加载图片并显示
12 Mat src = imread("D://XR//JZ//building1.jpg");
13 imshow("原图",src);
14
15 //灰度化
16 Mat grey;
17 cvtColor(src,grey,COLOR_BGR2GRAY);
18
19 //调用canny函数
20 Mat edge;
21 Canny(grey,edge,3,9,3);
22
23 //显示图片
24 imshow("结果", edge);
25 waitKey(0);
26 }
小编这周又要给小伙伴们讲课啦,学长给我安排的任务是边缘检测。小编翻了翻书,一共有70页。哇!!!范围好大,不过再多还是要讲的,只能跟中秋节说再见了,(╥╯^╰╥)。
小编还是先做个笔记吧,现在能写清楚,到时候就能说清楚。以下内容是我看了许多的博客,自己整合得来的,至于图都是盗来的。
首先,什么是边缘检测呢?
图像的边缘指的是灰度值发生急剧变化的位置。在小编看来,边缘检测是检测出物体的边缘并描绘出来形成一个线图。一般边缘检测都是通过计算梯度幅值,凸显出灰度强度有显著变化的点。
一般边缘检测的有3个步骤:先滤波消除噪声,再计算梯度找出灰度变化强烈的位置,最后阈值化检测找出物体边缘。
梯度:本意是一个向量(矢量),表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。梯度反映的是空间变量变化趋势的最大值和方向
梯度方向:是指局部增长最快的方向。以此类推,负梯度方向是指局部下降最快的方向。
边缘检测有很多方法,小编还是先讲一下常用的吧。
1.canny边缘检测
最优的边缘检测算法,先平滑后求导数的方法。
(1)高斯平滑滤波器(消除噪声)
图像矩阵I分别与水平方向上的卷积核sobel(x)和垂直方向上的卷积核sobel(y)卷积得到dx和dy。通常卷积矩阵为奇数。
待处理图像数据(5*5): 卷积核:(3*3)
A = [17 24 01 08 15 H = [8 1 6
23 05 07 14 16 3 5 7
04 06 13 20 22 4 9 2]
10 12 19 21 03
11 18 25 02 09]
步骤:
①将算子围绕中心旋转180度
H’=[2 9 4
7 5 3
6 1 8]
②滑动算子,每个像素相乘相加得到一个数,放入矩阵中间的位置。
例如:(2,4)元素值= 1* 2+ 8* 9+15* 4+ 7* 7+14* 5+16* 3+13* 6+20* 1+22* 8=575
遇到边界则赋值为0。
③重复①②的操作得到dx和dy。
(2)计算梯度幅值和方向(找出灰度变化强烈的地方)
利用高斯滤波得到卷积矩阵dx和dy,利用以下公式来计算:
(3)非极大值抑制(保留了极大值,抑制了非极大值,排除非边缘像素,仅保留了一些细线条)
对图像进行梯度计算后,仅仅基于梯度值提取的边缘仍然很模糊,所以要进行非极大值抑制。解决方法:利用梯度方向。
算法:①将当前像素的梯度强度与沿正负梯度方向上的两个像素进行比较。
②如果当前像素的梯度强度与另外两个像素相比最大,则该像素点保留为边缘点,否则该像素点将被抑制为0。
通常为了更加精确的计算,在跨越梯度方向的两个相邻像素之间使用线性插值来得到要比较的像素梯度,现举例如下:
如图3-2所示,将梯度分为8个方向,分别为E、NE、N、NW、W、SW、S、SE,其中0代表00~45o,1代表450~90o,2代表-900~-45o,3代表-450~0o。像素点P的梯度方向为theta,则像素点P1和P2的梯度线性插值为:
其中E、NE、W等表示该方向上的像素值。
因此非极大值抑制的伪代码描写如下:
(4)滞后阈值(还是有噪声,更准确的找出边缘。)
一般用双阈值检测,设置两个阈值,高阈值TH和低阈值TL。一般比率为2:1或3:1。
如果边缘像素的梯度值高于高阈值,则将其标记为1;如果边缘像素的梯度值小于高阈值并且大于低阈值,则使用8连通域确定,只有与TH像素连接时才会被接受标记成1;如果边缘像素的梯度值小于低阈值,则会被抑制为0。阈值的选择取决于给定输入图像的内容。
双阈值检测的伪代码描写如下:
4连通和8连通域:
所谓四连通区域或四邻域,是指对应像素位置的上、下、左、右,是紧邻的位置。共4个方向,所以称之为四连通区域,又叫四邻域。
所谓八连通区域或八邻域,是指对应位置的上、下、左、右、左上、右上、左下、右下,是紧邻的位置和斜向相邻的位置。共8个方向,所以称之为8连通区域或八邻域。
八连通则定义为:
即点(x,y)的8连通域指的是这个点周围的8个点,例如(x,y)的8联通区域为 (x-1,y-1);(x-1,y);(x-1,y+1); (x,y-1) ;(x,y+1); (x+1,y-1) ;(x+1,y);(x+1,y+1)。
将一个点a带入式子,若得出的坐标与b相同则两个点连通。
对每一个值为1的点若其八连通有一个点的值也为1,那么这两个点就归为一个物体。 从8连通的定义公式可以看到,其为N4四连通并上右下、右上、左下、左上四点,即四连通是八连通的子集。也就是说在图像处理中四连通的区域,一定是八连通。
从上图可以看到,4连通意义上,可以分成独立的三个区域。
在8连通意义上,同样的一个图像,只有一个区域。
原始图像:
边缘检测图像: