Sobel算子是用来提取图像边缘的,而边缘在灰度图中表现为灰度值变化剧烈的位置,可以用像素值差分结果的大小来表征变化剧烈与否。
离散情况下的差分对应的是连续域的微分,因此一般的边缘提取算子其思想都是求图像的微分,如1阶微分和2阶微分,同时又因为图像存在x和y两个方向,因此会出现偏微分。
Sobel算子原理
Sobel算子计算图像差分,依赖两个卷积核,如下图所示。
左侧代表在x方向上进行加权差分,右侧代表在y方向上的加权差分。此处要注意的是,卷积核在真正参与图像卷积的时候,要旋转180度,这与数字图像处理中的卷积定义有关。旋转之后形成的运算模板如下:
通过2个卷积核和图像卷积,可以得到两个方向上的差分图像。差分图像和源图像的尺寸相同,其像素值的含义:像素值越大,代表源图像在该位置处的差分结果越大。因此差分图像中灰度值越大(即越白)的点,是边缘的可能性越大。
通过一定的加权融合方法,融合两幅差分图像即可得到原始图像的边缘图像。
Opencv实现
在OpenCV里提供了sobel边缘提取的函数:
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
前四个是必须的参数:
src:需要处理的图像;
ddpteh:是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度 必须大于等于原图像的深度;
dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
可选的参数:
dst:目标图像
ksize:Sobel算子的大小,必须为1、3、5、7。
scale:是缩放导数的比例常数,默认情况下没有伸缩系数;
delta:是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType:判断图像边界的模式。这个参数默认值cv2.BORDER_DEFAULT。
图像深度参数
ddpteh这个参数代表dst图像的深度,可选的参数如CV_16S、CV_32F、CV_64F等。
由于Sobel算子计算的是差分,有正有负,并且可能存在超过255的数,因此如果采用8为深度的话,显示图像会有问题。
求导阶数
两个参数分别代表对x和y方向的求导阶数。
这里一个容易出问题的地方在于,如果两个参数都给1,理论上是对x和y方向上都求导,得到的应该是一个融合后的边缘图像。然而实际结果是,输出的边缘图像灰度值偏低,即边缘都特别浅。
正确的做法如下:
sobel_x = cv.Sobel(img_gussian, cv.CV_16S, 1, 0, 5)
sobel_y = cv.Sobel(img_gussian, cv.CV_16S, 0, 1, 5)
abs_x = cv.convertScaleAbs(sobel_x)
abs_y = cv.convertScaleAbs(sobel_y)
img_sobel = cv.addWeighted(abs_x,0.5, abs_y, 0.5, 0)
先分别得到两个方向上的差分图像,再对每个像素求绝对值;之后通过addWeighted函数进行加权融合。这样得到的边缘图像比较正常。
实例
这是对两个方向同时求导得到的结果,图像非常的浅。
从左到右分别是x方向差分图,y方向差分图,融合后的边缘图像。