边缘检测-上

1 什么是边缘?

图像的边缘时指图像局部区域亮度变化显著的部分

2 边缘检测

边缘检测,顾名思义,就是提取边缘。
边缘检测的原理是:在边缘部分,像素值会出现较大的变化,**在边缘部分求一阶导数,就会出现极值。而在一阶导数为极值的地方,二阶导数为0,基于这个原理,就可以进行边缘检测。**如下图所示:左边为图像,右边为对图像宽度方向求一阶导数导数的变化曲线图,图像的边缘位于黑白相接的地方,也是就是weight = 100,由右图可知,weight = 100是该处的一阶导数为最大值,因此该点就是边缘点。

在这里插入图片描述

常用的 方法有:
一阶导数:sobel、prewitt、Roberts等算子
二阶导数:Laplace、Canny算子

其中,Canny算子的效果最好,但是实现起来更麻烦。

3 常用算子的原理

边缘在一阶导数取最大值,二阶导数为0的地方,在图像处理中,将一阶导数最大值原理提取边缘的算子称为一阶微分边缘算子,将利用二阶导数为0的原理求边缘的算子称为二阶微分边缘算子。

3.1 一阶微分边缘算子

一阶微分边缘算子求边缘实际上就是求导数,那么在图像中导数该怎么计算?

设*f(x,y)*为点(x, y)对应的像素值大小,则图像在x方向和y方向的一阶微分算子应该计算为:
在这里插入图片描述
图像是离散的二维函数,∆x、∆y不能无限小,最小就是1像素。因此,上述公式就变成:

在这里插入图片描述
该式对应的算子是:
在这里插入图片描述

3.1.1 Prewitt 算子

利用上述的Gx, Gy来检测边缘还存在一个问题,就是噪声点会被误测为边缘。通常如果一个点是边缘点,那么它上面下面的点也为边缘点,而噪声却是一个孤立的点,因此,可以根据其上下点的梯度来判断该点是不是边缘点。相同时检测锚点及其上方下方点的梯度,只需将滤波器扩展为:

在这里插入图片描述
该算子可以用来检测边缘,但是它不是Prewitt 算子。真正的Prewitt 算子是:
在这里插入图片描述
利用 Prewitt 算子,计算出水平和垂直梯度的幅值,可以得到边缘的强度。对于某个像素点P,如果其水平和垂直梯度都较大,意味着其周围存在边缘,即捕捉到了上下文信息。反之,如果梯度较小,则说明该点周围没有明显的边缘。可以设定一阈值,大于阈值的为边缘,小于阈值的视为噪声点。
使用 Prewitt 算子进行边缘检测的代码如下:

import numpy as np
import cv2
import matplotlib.pyplot as plt

# 读取图像
image = cv2.imread('lenna.png', cv2.IMREAD_GRAYSCALE)

# 定义Prewitt算子模板
prewitt_x = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]])
prewitt_y = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]])

# 使用Prewitt算子进行边缘检测
gradient_x = cv2.filter2D(image, -1, prewitt_x)
gradient_y = cv2.filter2D(image, -1, prewitt_y)

# 将x、y梯度相加得到边缘图像
edge_image = cv2.add(np.abs(gradient_x), np.abs(gradient_y))

# 显示图像
plt.subplot(2, 2, 1), plt.imshow(image, cmap='gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 2, 2), plt.imshow(gradient_x, cmap='gray')
plt.title('Prewitt X'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 2, 3), plt.imshow(gradient_y, cmap='gray')
plt.title('Prewitt Y'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 2, 4), plt.imshow(edge_image, cmap='gray')
plt.title('Prewitt Edge'), plt.xticks([]), plt.yticks([])

plt.show()

运行结果如下:
在这里插入图片描述

3.1.2 Sobel检测算子

Sobel检测算子与Prewitt算子原理一样,他是Prewitt算子的一种特殊情况。**Sobel检测算子对像素的位置进行了加权,距离边缘更远的像素会被赋予较小的权重,而距离边缘更近的像素会被赋予较大的权重,使得边缘像素的响应更强烈。**其模板为:
在这里插入图片描述
使用 Sobel算子进行边缘检测的代码如下:

def sobel_edge_detection(image):

    # 对图像进行高斯模糊以减少噪声
    blurred = cv2.GaussianBlur(image, (3, 3), 0)

    # 计算x方向和y方向的梯度
    gradient_x = cv2.Sobel(blurred, cv2.CV_64F, 1, 0, ksize=3)
    gradient_y = cv2.Sobel(blurred, cv2.CV_64F, 0, 1, ksize=3)

    # 取绝对值并转换为8位无符号整数
    gradient_x = cv2.convertScaleAbs(gradient_x)
    gradient_y = cv2.convertScaleAbs(gradient_y)

    # 将x方向和y方向的梯度相加
    gradient = cv2.addWeighted(gradient_x, 0.5, gradient_y, 0.5, 0)

    # 显示图像
    plt.subplot(2, 2, 1), plt.imshow(image, cmap='gray')
    plt.title('Original Image'), plt.xticks([]), plt.yticks([])

    plt.subplot(2, 2, 2), plt.imshow(gradient_x, cmap='gray')
    plt.title('Prewitt X'), plt.xticks([]), plt.yticks([])

    plt.subplot(2, 2, 3), plt.imshow(gradient_y, cmap='gray')
    plt.title('Prewitt Y'), plt.xticks([]), plt.yticks([])

    plt.subplot(2, 2, 4), plt.imshow(gradient, cmap='gray')
    plt.title('Prewitt Edge'), plt.xticks([]), plt.yticks([])

    plt.show()

    '''
    # 显示图像和边缘图
    cv2.imshow('Original Image', image)
    cv2.imshow('X Direction Gradient', gradient_x)
    cv2.imshow('Y Direction Gradient', gradient_y)
    cv2.imshow('Combined Gradient', gradient)
    cv2.waitKey(0)
    cv2.destroyAllWindows()'''


# 读取图像
image = cv2.imread('lenna.png',  cv2.IMREAD_GRAYSCALE)

# 进行边缘检测
sobel_edge_detection(image)

代码运行结果如下:
在这里插入图片描述
可以看出Sobel比 Prewitt 算子的效果好。

3.1.2 Roberts算子

Roberts算子的两个模板如下:
在这里插入图片描述
Roberts算子计算的是对角线方向的梯度,由于其没有中心点,在实际中很少用

参考:
添加链接描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值