边缘检测(2):Sobel算子与Canny算子

5,134 阅读4分钟

上一篇文章介绍了边缘检测的一些基本概念。本文是边缘检测系列的第二篇,介绍两个成熟的边缘检测算法:Sobel算子和Canny算子。

Sobel算子

Sobel算子是基于梯度的边缘检测算法。 上一篇文章中我们已经得出结论:在图像中边缘所在的位置梯度较大。 而Sobel算子正是利用两个3×33\times3的卷积核,与图像做卷积,得出各处的梯度(两个卷积核分别为x方向和y方向)。

Sobel算子的两个卷积核分别如下:

Gx=[+101+202+101]Gy=[+1+2+1000121]G_x= \left[ \begin{matrix} +1&0&-1\\ +2&0&-2\\ +1&0&-1 \end{matrix} \right] G_y= \left[ \begin{matrix} +1&+2&+1\\ 0&0&0\\ -1&-2&-1 \end{matrix} \right]

Sobel卷积核的分解

上述的Sobel卷积核可以分解成为两部分,分别是高斯平滑和梯度计算:

Gx=[+101+202+101]=[121][+101]G_x= \left[ \begin{matrix} +1&0&-1\\ +2&0&-2\\ +1&0&-1 \end{matrix} \right]= \left[ \begin{matrix} 1\\ 2\\ 1 \end{matrix} \right] \left[ \begin{matrix} +1 & 0 & -1 \end{matrix} \right]

其中[121] \left[ \begin{matrix} 1\\ 2\\ 1 \end{matrix} \right]用来进行高斯平滑,[+101] \left[ \begin{matrix} +1 & 0 & -1 \end{matrix} \right]用来计算梯度。

Sobel算子的结果

和上一篇文章一样,通过以下公式计算得到结果的大小和方向:

G=Gx2+Gy2G=\sqrt{{G_x}^2+{G_y}^2}
Θ=arctan(GyGx)\Theta=\arctan \left( \frac{G_y}{G_x} \right)

总而言之,Sobel算子可以一步到位进行图像的平滑和梯度计算,图像经过Sobel算子得到的结果中值比较大的地方即为边缘所在地。

如下图所示,左上为原图,右上和左下分别为GyG_yGxG_x,右下为GG的结果。在右下图中较亮的地方为图像上的边缘(在实作时一般选取一定的阈值,大于阈值的像素被认为是边缘)。

image.png

Sobel算子的缺陷

Sobel算子是简单的边缘检测方法,其具有以下两方面缺陷:

  1. 局部性较差:GG仅为简单计算梯度,在边缘附近的几个像素均会出现值较大的情况,导致判断出的边缘“比较粗”
  2. 对于特定的方向较为敏感:Sobel算子只计算横向和纵向两个方向的梯度,对于斜向的边缘,容易被遗漏,同时在这两个方向上容易出现假阳性

Canny算子

和简单的Sobel算子相比,Canny算子考虑的情况更多、结果更准确,也是计算机视觉中更加常用的边缘检测算法。

上一节中的Sobel算子完成了两个步骤:一是利用高斯平滑来处理噪声,二是计算了图像梯度的强度和方向。 带来的缺点是结果的本地化不够好。 而Canny算子在Sobel算子的基础之上(即Canny算子中首先需要计算Sobel算子的结果),继续完成了两个步骤:

  • 非极大值压制
  • 利用迟滞阈值对边缘进行筛选

非最大值压制

上一节中我们得到的结论是Sobel算子的本地化不够好,这个问题在于我们把梯度的强度大于阈值的像素均认为是边缘。但实际上,假设一段区域的梯度值如下图所示,则只有在极大值的位置才应该被判断为边缘。

图片名称

如下图所示,假设G(x,y)|\nabla G|(x,y)为点(x,y)(x,y)的梯度值,则进行非极大值压制的公式如下(其中xx'xx''xx在边缘切向方向的相邻点)

图片名称
M(x,y)={G(x,y)ifG(x,y)>G(x,y)&G(x,y)>G(x,y)0otherwiseM(x,y)= \left\{ \begin{array}{lr} |\nabla G|(x,y)\quad if\quad |\nabla G|(x,y) > |\nabla G|(x',y')\quad \&\quad |\nabla G|(x,y) > |\nabla G|(x'',y'')\\ 0\quad otherwise \end{array} \right.

下图是经过非极大值压制处理以后边缘的变化,可以发现非极大值压制使得边缘更加精细。

image.png

迟滞阈值

到目前为止我们对于边缘的判断是通过单一的阈值,即把经过处理后梯度值比阈值大的点认为是边缘。 但单一的阈值很难选取,阈值过高容易造成边缘的不连续(如下左图),而阈值选取过低则会引入一些其他噪声(如下右图)

image.png

迟滞阈值法通过设定两个阈值(一个高阈值H和一个低阈值L)来解决这个问题:

  • 如果梯度值小于L,则不作为边缘
  • 如果梯度值大于H,则作为强边缘
  • 如果梯度值介于L和H之间,则作为弱边缘

强边缘直接被视为边缘,而弱边缘被选中作为边缘的条件是:

  • 直接与强边缘相连
  • 通过相邻的其它弱边缘与强边缘相连

Canny边缘检测算法流程

到目前为止我们已经介绍了Canny中的所有过程,总结如下:

  1. 首先对于图像进行高斯平滑并计算xxyy方向的梯度
  2. 计算梯度的值和方向
  3. 进行非极大值压制——减小边缘宽度
  4. 进行迟滞阈值法筛选

最终其效果如下:

image.png

本文总结

本文介绍了两种边缘检测算子——Sobel算子与Canny算子。 其中Sobel算子是基础而简单的,Canny算子更加常用和健壮。 下一篇文章中我们将介绍Canny边缘检测算法的Python实现,敬请期待。