编辑推荐: |
本文来自于csdn, 文章主要介绍了概念基础,Canny边缘检测算法流程以及高斯滤波,也介绍了计算图像的梯度及梯度的方向等等,详情请看下文。
|
|
0.何谓边缘
说起边缘,那肯定是图像中明暗变化比较剧烈的像素所组成的线条。从视觉的角度来讲,我们首先注意到的其实就是一些简单的线条,然后再由这些简单的线条组合成更加抽象的概念来使得我们能够认识出我眼前的是个啥。就好比下面的图,你光看那个边缘图,是不是大概就能看出来原图里是个女人?
右边的边缘图其实就是把原图中的边缘提取出来之后的图,从直觉上也能够看得出来,所谓的边缘检测无非就是对整个图的像素做像素级的二分类。要么是边缘点(用白色表示),要么不是边缘点(用黑色表示)。把这些点展示出来就成了边缘图。
当然边缘检测的算法有很多种,这篇博客就先简单哔哔一下最为经典的边缘检测算法—Canny!!
1.Canny边缘检测算法流程
其实Canny算法的步骤就那么几步:
1.高斯滤波
2.计算图像的梯度和梯度方向
3.非极大值抑制
4.双阈值筛选边缘
很明显第一步无非就是减少图像中的噪声,增强边缘检测的鲁棒性。第二步是想把边缘给强调出来,但是由于强调出来有二义性,所以用第三步来过滤一些边缘点。但是第三步可能过滤不干净,所以就有了第四步的套路来过滤干净。so。。。下面就一个一个的来哔哔。
2.高斯滤波
高斯滤波和其他的滤波器套路基本上一致,无非就是一个滤波核在原图上摩擦摩擦,一步一步似爪牙,似魔鬼的步伐。。。所以高斯滤波的效果如何,取决于滤波核的大小和里面的值。
那现在的主要矛盾就是滤波核里的值怎么来确定。其实非常简单,就是通过这么一个公式:
这个公式的意图是啥呢?其实就是个滤波核里的值尽量的填成一个二维的高斯分布。我们可以举个栗子:
1.假设我的滤波核是3*3的
2.假设我的高斯分布的标准差为1也就是σ=1
3.x和y代表滤波核中各个点相对于中心点的坐标,就像酱紫:
有了这些假设之后,我们就能很简单的把滤波核对应的值给算出来,就像酱紫:
但是这个时候算出来的值有个问题,如果把所有的9个值全加起来不等于1!!!(概率合应该为1)所以我们要对其进行归一化,让所有的9个值加起来等于1。其实归一化很简单,就是个9个值全加起来也就是(0.0585+0.0965+0.0585+…+0.0585=0.7792),然后把每个值都除以这个0.7792,就能得到归一化后的滤波核。(这个时候你会发现所有值全加起来等于1)
而且可以脑补一下,如果波滤核的size比较大,然后每个格子里面的值看成是概率的话。其实就可以脑补成酱紫的图(很明显的一个二维高斯分布):
确定了滤波核的值之后,就可以快乐的滤波了。
3. 计算图像的梯度和梯度的方向
要算图像的梯度,肯定会想到图像的梯度算子。在Canny中用到的梯度算子是Sobel算子,说是算子,其实就是滤波核。Sobel算子主要分为两个,一个是用来计算水平方向的梯度,另一个用来计算竖直方向的梯度。
所以,对原图用第一个滤波核就能算出图像的水平方向的梯度,用第二个滤波核就能算出图像的竖直方向的梯度。
有了两个方向的梯度之后,其实就能算出图像的梯度和梯度的方向了。因为已经有了水平和竖直了,要算总的梯度,无非就是勾股定理嘛~~~~
也就是说
图像的梯度值 = 开根号(竖直方向的梯度幅值的平方+水平方向的梯度幅值的平方)
图像的方向 = arctan(竖直方向的梯度幅值/水平方向的梯度幅值)
4. 非极大值抑制
假设现在拿到了梯度方向的图是酱紫:
梯度幅值的图是酱紫:
那如果要做非极大值抑制,就还需要个东西,就是这个:
这个表达的意思非常简单,中间的方块可以看成是一个3*3的区域,然后线代表的是角度。比如(-1,1)这个点的角度是45度,(0,
1)这个点的角度是0度。那这个东西有啥用呢,举个栗子:
如果我要对梯度幅值图里第2行第2列的那个点(值是144)做非极大值抑制,那我就看我对应的方向的值是多少,很明显是26。那26很明显和45度更加接近,所以我要做非极大值抑制的时候所要对比的梯度幅值的点就是45度那根线所对应的点,也就是5和3。此时可以看出,144>5并且144>3,所以144是个极大值点,所以这个点就不会被抑制。
那如果我要对梯度幅值图里第5行第2列的点(值是178)做非极大值抑制,那很明显它的方向也就是角度是7度,7度离0度更近,所以我要做非极大值抑制的时候所要对比的梯度幅值的点就是0度那根线所对应的点,也就是180和14。此时可以看出,178<180并且178>14,所以178不是个极大值点,所以这个点就要被舍弃,把他赋成0。
很明显,对整个图做完非极大值抑制之后,是极大值的点得到了保留,不是极大值的点就都赋成了0。
5.双阈值筛选边缘
我们要做边缘检测目的是把边缘点设置成255,非边缘点设置成0。但做完非极大值抑制之后,图中的点虽然有一部分已经被抑制成了0。但我们还不知道应该把剩下的哪些点设置成边缘点。那有的童鞋可能会觉得,我设个阈值不就好了?我梯度值大于某个阈值我就认为是边缘点。这样当然可以,但是效果不会太好。所以前辈们撸了个双阈值筛选边缘的套路。套路如图:
套路呢从图就能很容易的看出来,就是会有两个阈值A和B(A<B),如果我当前点的梯度值比A还小那我就认为不是边缘点,如果比B还大那肯定是边缘点。这个很容易理解。那介于A和B的点呢?Canny的策略是如果我这种介于AB之间的点他与大于B的点是联通的,那我就认为这个点事边缘点,否则就不是。这个套路其实很天朝的XX考试很相似,我考试的分数如果比分数线低,那肯定GG。如果我的分数比分数线高出很多,那就美滋滋。如果我的分数比较中庸,那我可能就会去找关系找大腿,如果关系够硬,那我可能就美滋滋了。
OK,这样一套流程下来,Canny边缘检测就做完了,希望这篇博客对想了解Canny算法大致流程的童鞋有一定的帮助。
|