3.6. 图像梯度

3.6.1. 目标

在本章中,我们将学习:

  • 查找图像梯度、边缘等

  • 我们将看到以下功能: 第二节索贝尔()沙尔()拉普拉斯()

3.6.2. 理论

OpenCV提供三种类型的梯度滤波器或高通滤波器:Sobel、Scharr和Laplacian。我们将看到他们每个人。

1. Sobel和Scharr衍生物

Sobel算子是一种高斯平滑加微分的联合算子,因此对噪声的抵抗能力更强。可以指定要获取的垂直或水平导数的方向(通过参数, yorderxorder 分别)。也可以通过参数指定内核的大小 ksize . 如果ksize=-1,则使用3x3 Scharr滤波器,其结果比3x3 Sobel滤波器更好。请参阅所用内核的文档。

2. 拉普拉斯导数

它计算图像的拉普拉斯关系, \(\Delta src = \frac{{\partial ^2{{src}}}}{{\partial x^2}} + \frac{{\partial ^2{{src}}}}{{\partial y^2}}\) 其中每个导数都是使用Sobel导数找到的。如果 ksize = 1 ,然后使用以下内核进行筛选:

\[\begin{split}\begin{aligned} kernel = \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{bmatrix} \end{aligned}\end{split}\]

3.6.3. 代码

下面的代码显示了一个图表中的所有运算符。所有的内核都是5x5大小。输出图像的深度通过-1得到np.uint8类型的结果。

>>> %matplotlib inline
>>> import cv2
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>>
>>> img = cv2.imread('/cvdata/dave.jpg',0)
>>>
>>> laplacian = cv2.Laplacian(img,cv2.CV_64F)
>>> sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
>>> sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)
>>>
>>> plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
>>> plt.title('Original'), plt.xticks([]), plt.yticks([])
>>> plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
>>> plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
>>> plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
>>> plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
>>> plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
>>> plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
>>>
>>> plt.show()
../_images/sec06-gradients_2_0.png

结果:

3.6.4. 一件重要的事!

在上一个示例中,输出数据类型是cv2.CV_8U或np.uint8。但有一个小问题。黑白过渡为正斜率(有正值),黑白过渡为负斜率(有负值)。因此,当您将数据转换为np.uint8时,所有负斜率都设为零。简单地说,你错过了这一点。

如果要检测两条边,更好的选择是将输出数据类型保持为一些更高的形式,如cv2.CV s、cv2.CV f等,取其绝对值,然后转换回cv2.CV u。下面的代码演示了水平Sobel筛选器的此过程和结果差异。

>>> import cv2
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>>
>>> img = cv2.imread('/cvdata/box.png',0)
>>>
>>> # Output dtype = cv2.CV_8U
>>> sobelx8u = cv2.Sobel(img,cv2.CV_8U,1,0,ksize=5)
>>>
>>> # Output dtype = cv2.CV_64F. Then take its absolute and convert to cv2.CV_8U
>>> sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
>>> abs_sobel64f = np.absolute(sobelx64f)
>>> sobel_8u = np.uint8(abs_sobel64f)
>>>
>>> plt.subplot(1,3,1),plt.imshow(img,cmap = 'gray')
>>> plt.title('Original'), plt.xticks([]), plt.yticks([])
>>> plt.subplot(1,3,2),plt.imshow(sobelx8u,cmap = 'gray')
>>> plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([])
>>> plt.subplot(1,3,3),plt.imshow(sobel_8u,cmap = 'gray')
>>> plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([])
>>>
>>> plt.show()
../_images/sec06-gradients_4_0.png

检查以下结果:

3.6.5. 额外资源

3.6.6. 练习