图像边缘检测 - 图像梯度与Canny算子

图像边缘检测 - 图像梯度与Canny算子

前言

这学期上数字图像处理,还是觉得很有意思的,在这里记录一下某些知识点。可能会贴一些公式,欢迎指出错误。

一阶与二阶差分

所谓边缘直观来看就是图像局部灰度值变化剧烈的区域,也常常包括物体的轮廓等。拿到边缘信息之后便可用于后续的图像分割和特征提取算法(比如霍夫变换)。提取边缘在某种程度上就是一种高通滤波,因此一个很直观的想法就是对图像求导。

设图像为 f(x,y)

用一阶差分近似一阶导数:

\frac{\partial f}{\partial x}=f(x+1)-f(x)

同理可以得到二阶差分:

\frac{\partial^2 f}{\partial x^2}=f(x+1)+f(x-1)-2f(x)

只考虑一个方向上像素的情况,注意到其中出现的各种边缘情况

我们对像素序列分别做一阶和二阶差分:

注意到一阶差分在斜边(Ramp)处有恒定的斜率响应,因此检测到的边缘存一个宽度;而二阶差分在所有边缘位置都会产生符号相反的两个峰值响应,因此我们可以利用过零点来寻找边缘的精确位置。

值得注意的是,由于差分对图像的高频成分十分灵敏,所以要特别注意噪声的影响。因此在做差分运算之前一般需要先进行模糊降噪处理。

图像梯度

现在考虑二维情况的一阶导数,即梯度

\nabla f(x) = \left[ \begin{array}{} g_{x}\\ g_{y}\\ \end{array} \right ] = \left[ \begin{array}{} \frac{\partial f}{\partial x}\\ \frac{\partial f}{\partial y}\\ \end{array} \right ]

我们即可以求出梯度向量的模和角度

M_{2}(x,y)=\sqrt{g_{x}^2 + g_{y}^2}

M_{1}(x,y)=|g_{x}| + |g_{y}|

M_{\infty}(x,y)=Max\{|g_{x}| , |g_{y}|\}

\alpha (x,y) = tan^{-1}\left[ \frac{g_{y}}{g_{x}} \right]

模值也可以用 L_{1} 或者L_{\infty} 范数来估计,在计算机实现上更为容易

梯度向量的几何意义如上图所示,模表示变化的剧烈程度,角度描述边缘的法线方向

梯度算子

在图像处理中一般使用卷积操作来完成各种空域线性运算,求导也是线运算,因此可以用卷积核(或者叫模板)来描述。

之前我们提到的最简单的一阶差分可以用以下kernel表示:

\left[ \begin{matrix} -1 \\ +1 \end{matrix} \right] \quad \left[ \begin{matrix} -1 & +1 \end{matrix} \right]

当然我们可以用2-D的kernel来描述两个对角方向的差分,即Roberts算子

\left[ \begin{matrix} -1 & 0\\ 0 & +1 \end{matrix} \right] \quad \left[ \begin{matrix} 0 & -1\\ +1 & 0 \end{matrix} \right]

但是这种 2\times2 的算子因为没有中心像素,实际用起来不太方便,因此一般用 3\times3 的算子

比如Prewitt算子:

\left[ \begin{matrix} -1 & -1 & -1\\ 0 & 0 & 0\\ +1 & +1 & +1 \end{matrix} \right] \quad \left[ \begin{matrix} -1 & 0 & +1\\ -1 & 0 & +1\\ -1 & 0 & +1 \end{matrix} \right]

与实际中很常用的Sobel算子:

\left[ \begin{matrix} -1 & -2 & -1\\ 0 & 0 & 0\\ +1 & +2 & +1 \end{matrix} \right] \quad \left[ \begin{matrix} -1 & 0 & +1\\ -2 & 0 & +2\\ -1 & 0 & +1 \end{matrix} \right]

不难发现这些 3\times3 的算子在计算中心位置的梯度时除了前后最近像素的差分,还使用了邻域内在所求方向上额外的两对像素,而Sobel算子还做了一定的加权,使得最近的那对像素权值更高,这种处理有利于减少噪声的影响。事实上它们可以分解为两个分差分和平滑算子。

\left[ \begin{matrix} -1 & -2 & -1\\ 0 & 0 & 0\\ +1 & +2 & +1 \end{matrix} \right] = \left[ \begin{matrix} -1 \\ 0 \\ +1 \end{matrix} \right] \left[ \begin{matrix} 1 & 2 & 1 \end{matrix} \right]

下面我们在实际图像上试试梯度算子的效果

利用色相表示梯度的方向(以 x 轴,即纵向为基准),明度表示梯度的模,可以观察到图像的边缘位置有强烈的响应,且可以得到边缘的法线方向。特别地,分别观察两个方向分量的模值,可以观察到在差分方向上响应最强,而与之正交方向几乎没有响应。

Canny边缘检测算法

虽然利用梯度能够大概确定边缘所在的区域,但并没有精确确定边缘的精确位置(只有一个像素宽的二值边缘),且我们希望去掉由于噪声或者不相关细节引入的假边缘。这个时候就要用到Canny边缘检测算法了。

Canny算法的三个检测标准:

  1. 低错误率,即得到的边缘尽可能包含真实的边缘而避免假边缘
  2. 高精确度,即得到的点尽可能落在真实边缘的中心
  3. 单一点响应,即一个边缘只会被标记一次,而不能出现模糊或者重边

Canny算法的输入就是我们刚才得到图像梯度的模值 M(x,y) 和角度 \alpha (x,y) ,但是在计算方向梯度之前需要先对原图像做高斯滤波以减少噪声的干扰。

为了得到精确的边缘,我们需要进行非极大值抑制,只确定一个局部极大值而将其他置零,从而去除边缘附近的模糊。

对于每一个以 p(x,y) 为中心的 3\times3 区域,通过其梯度角 \alpha (x,y) 可以确定此处边缘法线的4种朝向模式,即 x 方向, y 方向和两个对角方向,例如当匹配到如下模式时

比较中心像素与落在同样角度范围内的两个相邻像素 q,r 对应的梯度模值,如果为极大值则保留,否则表明该像素位置对边缘的响应不如它在同样法线方向上的相邻像素,因此距离边缘的正中位置较远,所以需要抑制掉。

另外还可以使用线性插值的方法直接计算 \alpha (x,y) 方向上对应的两个相邻点的值,但计算复杂度比方向匹配的方法更大。

此时的 M'(x,y) 在边缘处已经为单像素宽的的极大值灰度,为了去掉假边缘和得到二值化的输出,接下来要进行hysteresis阈值处理。

取两个阈值 T_{H},\ T_{L} 并对 M'(x,y) 进行筛选,得到:

M_{H}(x,y) = M'(x,y) ≥ T_{H}

M_{L}(x,y) = M'(x,y) ≥ T_{L} \ and\ M'(x,y) ≤ T_{H}

其中 M_{H}(x,y) 中的点超过高阈值 T_{H} ,直接可以判定为有效边缘

低于低阈值 T_{L} 的点直接扔掉,而 M_{L}(x,y) 中的点属于模棱两可的,如果它和有效边缘的点邻接(比如8邻接),那么也认为是有效边缘点(比如上图中属于C段的点),否则是假边缘上的点(比如B段)。因此我们从已经确定的有效边缘 M_{H}(x,y) 开始扩张,在 M_{L}(x,y) 里面寻找到邻接点,置为有效并放入 M_{H}(x,y) ,(这个操作可以用栈来描述,因为是First-In-Last-Out的)这样直到所有的有效点都遍历完成,将 M_{L}(x,y) 中未遍历的点全部扔掉,并将此时的 M_{H}(x,y) 二值化输出,便得到了最终的边缘检测结果。

原始图像:

Canny边缘检测结果:


编辑于 2019-05-01 20:40