首页 > 解决方案 > 如何使用 np.gradient 模拟 cv2.Sobel?

问题描述

我想在 x 轴和 y 轴差分方向上获取图像。但是,我想使用np.gradient函数编码,而不使用cv2.Sobel过滤器。

所以,我想像这样转换代码

x_grad = cv2.Sobel(image1, cv2.CV_64F, 1, 0, ksize=5)

像这样

x_grad = np.gradient(image1, axis=0)

但是,价值观不一样。我应该如何解决它?

标签: pythonnumpyopencvcomputer-visiongradient

解决方案


np.gradient功能有限,只有少数情况cv2.Sobel可以以某种方式复制,即以下:

import cv2
import numpy as np

image = cv2.imread('path/to/your/image.png', cv2.IMREAD_GRAYSCALE)

grad_cv2 = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=1)
grad_np = 2 * np.gradient(image, axis=1)
grad_np[:, [0, -1]] = 0
print(np.all(grad_cv2 == grad_np))
# True

grad_cv2 = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=1)
grad_np = 2 * np.gradient(image, axis=0)
grad_np[[0, -1], :] = 0
print(np.all(grad_cv2 == grad_np))
# True

grad_cv2 = cv2.Sobel(image, cv2.CV_64F, 1, 1, ksize=3)
grad_np = 2 * np.gradient(2 * np.gradient(image, axis=1), axis=0)
grad_np[:, [0, -1]] = 0
grad_np[[0, -1], :] = 0
print(np.all(grad_cv2 == grad_np))
# True

需要因子2,因为默认情况下np.gradient除以。2

由于以下原因(我强调),必须将边框设置为零:

梯度是使用内部点的二阶精确中心差异和边界处的一阶或二阶精确单侧(前向或后向)差异计算的。

另一方面,cv2.Sobel默认情况下,使用cv2.BORDER_REFLECT_101,以便您始终获得0边框。

大多数其他情况cv2.Sobel将涉及(高斯)平滑,参见。链接的文档:

Sobel 算子结合了高斯平滑和微分,因此结果或多或少能抵抗噪声。

不能单独使用np.gradient. 如果你想拥有它,你将cv2.Sobel使用 NumPy 方法重写。

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.16299-SP0
Python:        3.9.1
NumPy:         1.20.2
OpenCV:        4.5.1
----------------------------------------

推荐阅读