上一篇文章介绍了边缘检测的一些基本概念。本文是边缘检测系列的第二篇,介绍两个成熟的边缘检测算法:Sobel算子和Canny算子。
Sobel算子
Sobel算子是基于梯度的边缘检测算法。 上一篇文章中我们已经得出结论:在图像中边缘所在的位置梯度较大。 而Sobel算子正是利用两个的卷积核,与图像做卷积,得出各处的梯度(两个卷积核分别为x方向和y方向)。
Sobel算子的两个卷积核分别如下:
Sobel卷积核的分解
上述的Sobel卷积核可以分解成为两部分,分别是高斯平滑和梯度计算:
其中用来进行高斯平滑,用来计算梯度。
Sobel算子的结果
和上一篇文章一样,通过以下公式计算得到结果的大小和方向:
总而言之,Sobel算子可以一步到位进行图像的平滑和梯度计算,图像经过Sobel算子得到的结果中值比较大的地方即为边缘所在地。
如下图所示,左上为原图,右上和左下分别为和,右下为的结果。在右下图中较亮的地方为图像上的边缘(在实作时一般选取一定的阈值,大于阈值的像素被认为是边缘)。
Sobel算子的缺陷
Sobel算子是简单的边缘检测方法,其具有以下两方面缺陷:
- 局部性较差:仅为简单计算梯度,在边缘附近的几个像素均会出现值较大的情况,导致判断出的边缘“比较粗”
- 对于特定的方向较为敏感:Sobel算子只计算横向和纵向两个方向的梯度,对于斜向的边缘,容易被遗漏,同时在这两个方向上容易出现假阳性
Canny算子
和简单的Sobel算子相比,Canny算子考虑的情况更多、结果更准确,也是计算机视觉中更加常用的边缘检测算法。
上一节中的Sobel算子完成了两个步骤:一是利用高斯平滑来处理噪声,二是计算了图像梯度的强度和方向。 带来的缺点是结果的本地化不够好。 而Canny算子在Sobel算子的基础之上(即Canny算子中首先需要计算Sobel算子的结果),继续完成了两个步骤:
- 非极大值压制
- 利用迟滞阈值对边缘进行筛选
非最大值压制
上一节中我们得到的结论是Sobel算子的本地化不够好,这个问题在于我们把梯度的强度大于阈值的像素均认为是边缘。但实际上,假设一段区域的梯度值如下图所示,则只有在极大值的位置才应该被判断为边缘。
如下图所示,假设为点的梯度值,则进行非极大值压制的公式如下(其中和是在边缘切向方向的相邻点)
下图是经过非极大值压制处理以后边缘的变化,可以发现非极大值压制使得边缘更加精细。
迟滞阈值
到目前为止我们对于边缘的判断是通过单一的阈值,即把经过处理后梯度值比阈值大的点认为是边缘。 但单一的阈值很难选取,阈值过高容易造成边缘的不连续(如下左图),而阈值选取过低则会引入一些其他噪声(如下右图)
迟滞阈值法通过设定两个阈值(一个高阈值H和一个低阈值L)来解决这个问题:
- 如果梯度值小于L,则不作为边缘
- 如果梯度值大于H,则作为强边缘
- 如果梯度值介于L和H之间,则作为弱边缘
强边缘直接被视为边缘,而弱边缘被选中作为边缘的条件是:
- 直接与强边缘相连
- 通过相邻的其它弱边缘与强边缘相连
Canny边缘检测算法流程
到目前为止我们已经介绍了Canny中的所有过程,总结如下:
- 首先对于图像进行高斯平滑并计算和方向的梯度
- 计算梯度的值和方向
- 进行非极大值压制——减小边缘宽度
- 进行迟滞阈值法筛选
最终其效果如下:
本文总结
本文介绍了两种边缘检测算子——Sobel算子与Canny算子。 其中Sobel算子是基础而简单的,Canny算子更加常用和健壮。 下一篇文章中我们将介绍Canny边缘检测算法的Python实现,敬请期待。