📜  使用 Prewitt、Scharr 和 Sobel 算子进行边缘检测(1)

📅  最后修改于: 2023-12-03 14:49:44.998000             🧑  作者: Mango

使用 Prewitt、Scharr 和 Sobel 算子进行边缘检测

边缘检测是计算机视觉的一个重要应用。其目的是识别出图像中的物体边缘,常常作为其他图像处理任务的前置处理步骤,如目标识别、图像分割等。

边缘检测常用的算法有很多种,其中 Prewitt、Scharr 和 Sobel 算子是最常用的三种算法。其原理都基于图像微分,通过计算图像像素在 x、y 方向的微分变化,得到梯度值,进而识别出边缘。

下面介绍如何使用这三种算子进行边缘检测。

准备工作

我们先导入必要的库:

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

然后读入一张测试图片:

img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
Prewitt 算子

Prewitt 算子是由 Judith M. S. Prewitt 在 1970 年提出的。其对图片进行水平与垂直方向的像素微分,再将微分结果求和得到边缘梯度值,得到的结果类似于 Sobel 算子。

使用 OpenCV 中的 cv2.filter2D() 函数可以很方便地实现 Prewitt 算子:

kernelx = np.array([[1,1,1],[0,0,0],[-1,-1,-1]],dtype=int)
kernely = np.array([[-1,0,1],[-1,0,1],[-1,0,1]],dtype=int)
prewittx = cv2.filter2D(img, -1, kernelx)
prewitty = cv2.filter2D(img, -1, kernely)
prewitt = prewittx + prewitty

上述代码分别定义了一个水平方向的卷积核和一个垂直方向的卷积核,然后分别使用 cv2.filter2D() 函数对图片进行卷积操作,并将结果相加,得到边缘梯度值。

我们把 Prewitt 算子的输出结果进行可视化:

plt.subplot(1,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1,2,2),plt.imshow(prewitt,cmap = 'gray')
plt.title('Prewitt'), plt.xticks([]), plt.yticks([])
plt.show()
Scharr 算子

Scharr 算子是一种增强的 Sobel 算子,它同样通过像素微分计算图像梯度。Scharr 算子比 Sobel 算子更准确,因为它在 x 和 y 方向的微分值更加平衡,并且使用了更大的核。

同样地,使用 OpenCV 中的 cv2.filter2D() 函数可以实现 Scharr 算子:

scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharr = scharrx + scharry

上述代码用 cv2.Scharr() 函数分别计算了 x 和 y 方向的微分值,然后将其相加并取绝对值,得到了 Scharr 算子的输出。

我们也对 Scharr 算子的输出结果进行可视化展示:

plt.subplot(1,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1,2,2),plt.imshow(scharr,cmap = 'gray')
plt.title('Scharr'), plt.xticks([]), plt.yticks([])
plt.show()
Sobel 算子

Sobel 算子是最早提出的边缘检测算法之一,其原理与 Prewitt 算法类似。Sobel 算子对图片进行 x、y 方向的微分,再将其相加,得到边缘梯度值,因此其结果也类似于 Prewitt 算子。

对于 Sobel 算子,同样可以使用 OpenCV 中的 cv2.filter2D() 函数进行计算:

sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobel = sobelx + sobely

上述代码使用 cv2.Sobel() 函数分别计算了 x 和 y 方向的微分值,然后将其相加并取绝对值,得到了 Sobel 算子的输出。

最后,我们也对 Sobel 算子的输出结果进行可视化展示:

plt.subplot(1,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1,2,2),plt.imshow(sobel,cmap = 'gray')
plt.title('Sobel'), plt.xticks([]), plt.yticks([])
plt.show()

完整代码如下:

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

# 读入测试图片
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)

# 计算 Prewitt 算子
kernelx = np.array([[1,1,1],[0,0,0],[-1,-1,-1]],dtype=int)
kernely = np.array([[-1,0,1],[-1,0,1],[-1,0,1]],dtype=int)
prewittx = cv2.filter2D(img, -1, kernelx)
prewitty = cv2.filter2D(img, -1, kernely)
prewitt = prewittx + prewitty

# 计算 Scharr 算子
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharr = scharrx + scharry

# 计算 Sobel 算子
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobel = sobelx + sobely

# 可视化展示
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(prewitt,cmap = 'gray')
plt.title('Prewitt'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(scharr,cmap = 'gray')
plt.title('Scharr'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobel,cmap = 'gray')
plt.title('Sobel'), plt.xticks([]), plt.yticks([])

plt.show()

以上就是使用 Prewitt、Scharr 和 Sobel 算子进行边缘检测的介绍。这三种算子的应用非常广泛,可以用于目标识别、图像分割、模式识别等任务。在实际应用中,需要根据具体问题的要求选择最合适的算法和参数,才能达到最好的效果。