opencv-python 4.6. 图形梯度

发布时间 2023-03-30 10:18:43作者: 一枚码农

理论

OpenCV提供三种类型的梯度滤波器或高通滤波器,Sobel,Scharr和Laplacian。

  1. Sobel和Scharr
    Sobel算子是高斯联合平滑加微分运算,因此它更能抵抗噪声。你可以指定要采用的导数的方向,垂直或水平(yorder和xorder),你还可以通过参数ksize指定卷积核的大小。如果ksize = -1,则使用3x3的Scharr滤波器,其结果优于3x3的Sobel滤波器。
  2. Laplacian算子
    它的计算由关系给出的图像的拉普拉斯(Laplacian)算子,$$ \Delta src= \frac{\partial ^{2}src}{\partial x^{2}}+ \frac{\partial ^{2}src}{\partial y^{2}} $$,其中使用Sobel导数找到每个导数。 如果ksize = 1,则使用以下卷积核进行过滤:
    $$kernel=\begin{bmatrix} \ 0\ \ \ \ 1\ \ \ \ 0\ \ 1\ -4\ \ 1\ \ 0\ \ \ \ 1\ \ \ \ 0 \end{bmatrix}$$

代码实现

下面的代码显示了单个图表中的所有运算符,所有卷积核都是5x5大小。输出图像的深度为-1,以获得np.uint8类型的结果。

import cv2 as cv
from matplotlib import pyplot as plt

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\bg2.jpg', 0)

# 拉普拉斯
laplacian = cv.Laplacian(img, cv.CV_64F)

# Sobel x方向求导
sobelx = cv.Sobel(img, cv.CV_64F, 1, 0, ksize=5)

# Sobel y方向求导
sobely = cv.Sobel(img, cv.CV_64F, 0, 1, ksize=5)

plt.subplot(1, 4, 1), plt.imshow(img, cmap='gray'), plt.title('original')
plt.xticks([]), plt.yticks([])

plt.subplot(1, 4, 2), plt.imshow(laplacian, cmap='gray'), plt.title('laplacian')
plt.xticks([]), plt.yticks([])

plt.subplot(1, 4, 3), plt.imshow(sobelx, cmap='gray'), plt.title('sobelx')
plt.xticks([]), plt.yticks([])

plt.subplot(1, 4, 4), plt.imshow(sobely, cmap='gray'), plt.title('sobely')
plt.xticks([]), plt.yticks([])

plt.show()

image

一个重要的事情

在我们的上一个示例中,输出数据类型为cv.CV_8U或np.uint8,但是这有一个小问题,将黑到白转换视为正斜率(它具有正值),而将白到黑转换视为负斜率(它具有负值)。因此,当你将数据转换为np.uint8时,所有负斜率都为零。简单来说,你丢掉了所有的边界。

如果要检测两个边,更好的选择是将输出数据类型保持为某些更高的形式,如cv.CV_16S,cv.CV_64F等,取其绝对值,然后转换回cv.CV_8U。下面的代码演示了水平Sobel滤波器的这个过程以及结果的差异。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\bg3.jpg', 0)

# Output dtype = cv.CV_8U
sobelx8u = cv.Sobel(img, cv.CV_8U, 1, 0, ksize=5)

# Output dtype = cv.CV_64F. Then take its absolute and convert to cv.CV_8U
sobelx64f = cv.Sobel(img, cv.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()

image