本篇是边缘检测系列的第一篇,将大致介绍边缘检测的目的以及一些基础知识。
本文部分素材来源于Stanford大学的CS131课程。
边缘检测的目的
边缘检测顾名思义就是检测图像中的物体边缘,对于计算机来说,通过对边缘的检测可以提取相关的信息,从而进行对物体的识别。
本质上来说,边缘检测就是检测图片上的不连续成分,这些不连续包括:物品表面普通的不连续、深度的不连续、表面颜色的不连续以及光照强度的不连续等。
图像的梯度
既然边缘检测的重点是图片上的不连续成分,那很显然梯度是判断连续性的主要工具(这里连续与数学意义上的连续不是同一概念,在数学上不连续函数是不可导的)。 梯度的本意是一个向量(矢量),表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。 对图像求梯度,即意味着需要在二维空间中求离散梯度。
二元梯度
假设有二元函数,则有其梯度向量:
梯度值:
梯度方向:
二元离散梯度滤波器
若要对一个图像(即二维矩阵)求梯度,其横向滤波器为:
纵向滤波器为:
比如对于矩阵:
将上述横向滤波器作用于,得到:
下图为将一张图片横向纵向分别求导的结果:
简单的边缘检测器
边缘的特征
最简单的边缘检测器就是检测图像上强度变化剧烈的地方。 比如对于下面左侧图中红线一行的强度变化如右上图所示,可以明显观察到,有边缘的地方,强度变化十分剧烈。 二如果对强度函数求离散梯度,即可得到右下图,梯度值较大的地方即为强度函数变化剧烈的地方,也就是图像上边缘所在地方。
利用上一节中我们已经得到的梯度向量公式、梯度值公式和梯度方向公式即可求出图像上每一点的梯度。
噪声的影响与解决方法
上一小节中我们得到了边缘的特征——即图像强度的梯度值较大的地方,但实际情况并不如此美好。 图像上经常会有很多噪声,这些在这些噪声所在的地方我们的梯度值往往会变得很大,依照我们对边缘特征的定义,就会把这些噪声也视作边缘,导致我们找不到真正的边缘所在:
对于这种噪声,我们的解决方案是对图像进行平滑处理,使得那些和相邻的像素均显著不同的像素“看起来”更像周围的像素。
具体对图像进行平滑的方式,一般采用高斯平滑,其在二维空间的定义为:
其中和是两个方向的模糊范围,为标准差。 在离散空间中,分布不为零的像素组成的卷积矩阵与原始图像做变换。每个像素的值都是周围相邻像素值的加权平均。原始像素的值有最大的高斯分布值,所以有最大的权重,相邻像素随着距离原始像素越来越远,其权重也越来越小。这样进行模糊处理比其它的均衡模糊滤波器更高地保留了边缘效果。关于从连续高斯函数到离散空间形式的变换,可参考维基百科上尺度空间变换这一篇。
使用numpy产生高斯核的代码如下:
def gaussian_kernel(size, sigma):
kernel = np.zeros((size, size))
k = int((size - 1) / 2)
parameter = 1 / (2 * np.pi * sigma ** 2)
for i in range(2 * k + 1):
for j in range(2 * k + 1):
kernel[i][j] = parameter * np.exp(-((i - k) ** 2 + (j - k) ** 2) / (2 * sigma ** 2))
return kernel
比如产生大小为,标准差为1的高斯核,结果为:
经过高斯平滑后,上图中带噪声的函数即可得到“干净”的梯度函数:
在高斯函数参数的选择上,要注意平滑度与局部化之间的平衡,如果平滑程度过高,会将原有的边缘模糊掉,导致我们的目标发生偏离。
什么是好的边缘检测器
设计一个好的边缘检测器,有以下三个原则:
- 检测准确度高:一个好的边缘检测器必须尽可能降低假阳性(即由于噪声导致检测到原本不存在的边缘)和假阴性(真正的边缘没有被检测到)
- 局部化程度高:检测出的边缘必须与真实边缘尽可能贴近
- 单一响应:检测器对于一个真实边缘只能检测出一条边,即最小化真实边缘附近的局部最大值
本文小结
本文简单介绍了边缘检测的目标以及一些基础知识,下一篇文章将介绍几个经典的边缘检测器。