如何使用 OpenCV 将梯度/幅度应用于图像?
Posted
技术标签:
【中文标题】如何使用 OpenCV 将梯度/幅度应用于图像?【英文标题】:How to apply gradient/magnitude to an image using OpenCV? 【发布时间】:2021-08-14 18:45:21 【问题描述】:我目前正在关注this tutorial,作为大学作业的一部分,我们应该自己实现精明的边缘检测。应用高斯模糊没有任何问题,但现在我正在尝试显示网站上显示的幅度强度。
我实现了上述网站上的功能,并创建了一个运行精明边缘检测的功能。目前这是函数的样子:
def canny_edge(img):
noise_reduction = cv.filter2D(img, -1, gaussian_kernel(5))
cv.imshow('Blur', noise_reduction)
magnitude, gradient = sobel_filters(img)
magnitude = magnitude.astype(np.uint8)
sobel = magnitude * gradient
sobel = sobel.astype(np.uint8)
test = img + (255 - gradient * noise_reduction)
plt.imshow(gradient, cmap='gray')
plt.show()
cv.imshow('Gradient', magnitude)
cv.imshow('Original Image', img)
我必须将幅度和 sobel 数组转换为 np.uint8
,否则它们将包含 float
值,这会在显示图像时导致错误。目前,我正在使用变量test
来尝试各种事情,比如gradient - noise_reduction
,你在上面看到的那行等等。问题是我总是得到看起来与这些相似的图像(左边的图像显示@987654333 @,右图为gradient
,下图为magnitude
):
我对所有可用的 OpenCV 函数都不太熟悉,但我想使用其中一些我不知道的函数可能很重要。不幸的是,在上面链接的教程中,我无法找到有关sobel_filters
函数返回的幅度如何应用于图像的任何信息。提前感谢您提供有关如何解决此问题的任何意见。
【问题讨论】:
我认为您可能需要在.astype(np.uint8)
之前添加.clip(0,255)
。看起来你正在接受强度环绕。
好的,我在将数组转换为np.uint8
之前直接输入了magnitude = magnitude.clip(0,255)
行,我仍然得到相同的结果,所以我想这不是问题。我还假设.clip(0,255)
只是确保值在 0 到 255 之间,但据我记得,如果值高于 255,OpenCV 还会向控制台打印警告,并说明自动将它们剪裁为 255。但仍然感谢为了这个想法。
什么工具或代码提供sobel_filters()
?这是否给出了索贝尔梯度的 x 和 y 分量或大小和方向?您将输出标记为幅度和梯度。对于 sobel 操作,这对我来说似乎不正确,它通常只提供梯度的 x 和 y 分量。
该功能在我链接的网站上定义。如果我正确理解了该网站,它会在 x 和 y 方向上应用 Sobel 算子并返回“梯度的幅度 G 和斜率 θ”。至少那是直接写在 code-sn-p 上方的内容,并且实际上对应于正在返回的变量。并且由于变量是根据给出的梯度大小及其方向的数学公式计算的,因此确实应该是函数提供的。
这一切似乎都是正确的。您是否查看了每个步骤以确保结果看起来合理?
【参考方案1】:
我认为 ndimage.filters.convolve 可能存在问题。我得到了和你相似的结果。但以下似乎使用 Python/OpenCV 可以正常工作
输入:
import cv2
import numpy as np
import skimage.exposure
img = cv2.imread('black_dress.png', cv2.IMREAD_GRAYSCALE)
img = cv2.GaussianBlur(img, (0,0), sigmaX=1.5, sigmaY=1.5)
Kx = np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])
Ky = np.array([[1, 2, 1],
[0, 0, 0],
[-1, -2, -1]])
Ix = cv2.filter2D(img, -1, Kx)
Iy = cv2.filter2D(img, -1, Ky)
G = np.hypot(Ix, Iy)
G = skimage.exposure.rescale_intensity(G, in_range='image', out_range=(0,255)).astype(np.uint8)
theta = np.arctan2(Iy, Ix)
theta = skimage.exposure.rescale_intensity(theta, in_range='image', out_range=(0,255)).astype(np.uint8)
cv2.imwrite('black_dress_gradient_magnitude.png', G)
cv2.imwrite('black_dress_gradient_direction.png', theta)
cv2.imshow("magnitude", G)
cv2.imshow("direction", theta)
cv2.waitKey(0)
幅度:
方向:
【讨论】:
我可以得到 scipy.ndimage.convolve 来给出类似的结果。需要使输入图像浮动,或者至少我在高斯滤波器之后做了浮动。 另一条评论。 OpenCV 的 filter2D 进行相关而不是真正的卷积。所以在 scipy 中,你需要使用 correlate 而不是 convolve 来获得相似的极性,这只会影响方向,而不是大小。以上是关于如何使用 OpenCV 将梯度/幅度应用于图像?的主要内容,如果未能解决你的问题,请参考以下文章