边缘检测Sobel、laplacian、canny算子

1.图像边缘检测

图像边缘检测对于分析图像中的内容、实现图像中物体的分割、定位等具有重要的作用。边缘检测大大减少了源图像的数据量,剔除了与目标不相干的信息,保留了图像重要的结构属性。常用的图像边缘检测方法分为以下两种:

  1. 一阶导数的边缘算子:
    通过模板作为核与图像的每个像素点做卷积和运算,然后选取合适的阈值来提取图像的边缘。代表算子为sobel、scharr算子。
  2. 二阶导数的边缘算子:
    通过求取二阶导数为0来寻找边界,代表laplacian算子。
    边缘检测Sobel、laplacian、canny算子_第1张图片

2.Sobel算子

2.1Sobel算子原理:

sobel算子需要先将图像转为灰度图,然后通过图像平滑操作,进行过滤噪声,然后使用sobel算子。
转化为灰度图像后用图像与卷积因子进行卷积运算。分别得到x方向和y方向的梯度值。
边缘检测Sobel、laplacian、canny算子_第2张图片
分别求水平Gx和竖直方向的导数Gy。
在这里插入图片描述
再求出该点整体的导数。得到该点的导数的方法有很多,可以用平方根的方式,或者绝对值求和等。下面展示平方根的方法。
在这里插入图片描述
得到的G可以与设定的阈值进行比较,如果大于某一阈值,可以认为该点为边缘点。

2.2代码实现

自定义sobel边缘检测算法:
def calculate_Sobel(img, threshold):
    height,width  = img.shape[::-1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = sum(sum(G_x * img[i:i + 3, j:j + 3]))
            h = sum(sum(G_y * img[i:i + 3, j:j + 3]))
            result[i + 1, j + 1] = np.sqrt((v ** 2) + (h ** 2))
    for i in range(0, width):
        for j in range(0, height):
            if result[i, j] < threshold:
                result[i, j] = 0
    return result

边缘检测Sobel、laplacian、canny算子_第3张图片

2.3API接口

cv.Sobel(src,depth,dx,dy,dst,ksize,scale,delta,borderType)

src:传入的图像
ddepth:图像的深度
dx dy:指求导的阶数。0表示这个方向上没有求导,取值为0、1。
ksize:指Sobel算子的大小,即卷积核的大小,必须为奇数1、3、5、7,默认为3。
注意:如果ksize = -1,就演变为3*3的Scharr算子。
scale:缩放导数的比例常数,默认情况为没有伸缩系数。
borderType:图像边界的模式,默认cv2.BORDER_DEFAULT。
注:Sobel算子是在两个方向计算的,最后还需要用cv2.addWeighted()函数将其组合起来.

#Api代码:
x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
Scale_absX = cv2.convertScaleAbs(x)
Scale_absY = cv2.convertScaleAbs(y)
result = cv2.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)

3.Laplacian算子

3.1laplacian算子原理

对x和y的二阶求偏导相加
边缘检测Sobel、laplacian、canny算子_第4张图片
因此,laplacian算子的卷积核如下。还是用图像与卷积核相乘。该点的梯度值就是周围的值相加 - 中心值的四倍。
边缘检测Sobel、laplacian、canny算子_第5张图片

3.2代码实现

#自定义
def calculate_laplacian(img):
    temLaplacian = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
    height, width = img.shape[::-1]
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            result[i + 1][j + 1] = np.abs(sum(sum(temLaplacian * img[i:i + 3, j:j + 3])))
    return result

API接口:

cv.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]]) 

ddepth:输出图片的数据深度
dst:输出图像,大小和类型与 src 相同
ksize:计算二阶导数滤波器的孔径大小,必须为正奇数,可选项
scale:缩放比例因子,可选项,默认值为 1
delta:输出图像的偏移量,可选项,默认值为 0
borderType:边界扩充的类型,注意不支持对侧填充(BORDER_WRAP)
边缘检测Sobel、laplacian、canny算子_第6张图片

4.Canny算子

Canny算子在检测算法中比较优秀。该算法的步骤如下:
1.高斯平滑进行降噪
2.计算梯度强度和方向。采用的是sobel算子
3.非极大值抑制。通常灰度变化的地方都比较集中,将局部范围内的梯度方向上,灰度变化最大的保留下来,其它的不保留,这样可以剔除掉一大部分的点。将有多个像素宽的边缘变成一个单像素宽的边缘。即“胖边缘”变成“瘦边缘”。
4.双阈值筛选。通过非极大值抑制后,仍然有很多的可能边缘点,进一步的设置一个双阈值,即低阈值(low),高阈值(high)。灰度变化大于high的,设置为强边缘像素,低于low的,剔除。在low和high之间的设置为弱边缘。进一步判断,如果其领域内有强边缘像素,保留,如果没有,剔除。

Api接口如下:

Canny(image, th1, th2, edges=None, apertureSize=None, L2gradient=None)

image参数表示8位输入图像。
threshold1参数表示设置的低阈值。
threshold2参数表示设置的高阈值,一般设定为低阈值的3倍 (根据Canny算法的推荐)。
edges参数表示输出边缘图像,单通道8位图像。
apertureSize参数表示Sobel算子的大小

blur = cv.GaussianBlur(image, (3, 3), 0)
edge_output = cv.Canny(img, 50, 150)

边缘检测Sobel、laplacian、canny算子_第7张图片

5.总结

Laplacian算子对噪声比较敏感,由于其算法可能会出现双像素边界,常用来判断边缘像素位于图像的明区或暗区,很少用于边缘检测;Sobel算子考虑了综合因素,对噪声较多的图像处理效果更好。canny算子效果比较好,对于噪声比较敏感,结合几种不同算子的优点衍生而来。

你可能感兴趣的:(图像处理,机器学习,python,算法,计算机视觉,图像处理)