Otsu 阈值化和图像梯度方向

Otsu Thresholding and Image gradient orientation

我想对图像梯度应用 Otsu 阈值处理(以去除噪声)。之后,我想计算梯度方向。不幸的是,当我这样做时,我只能得到 0 到 90 度之间的梯度方向。没有 Otsu 阈值,值介于 0 和 360 之间。

在Python

中查看我的代码
import numpy as np
import cv2

img = cv2.imread('Ob.png',cv2.IMREAD_GRAYSCALE)
img = img.astype('float32')
img2 = 
dst1 = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
dst2 = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)

ret1,th1 = cv2.threshold(dst1.astype(np.uint8),0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
ret2,th2 = cv2.threshold(dst2.astype(np.uint8),0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

mag, ang = cv2.cartToPolar(dst1.astype(np.float32),dst2.astype(np.float32))
np.rad2deg(ang)

如果我可以的话,为什么你做的第一件事就是将数据转换为 float32?

我认为在 Sobel 处理过程中让它这样做会更有效率。 这只是我的观点。

您命名为 "noise" 的梯度过滤器结果实际上称为非最大值。 通常,像 Canny 这样的算法确实包括在 Sobel 过滤之后对其进行阈值处理。 这种方法的不便在于找到合适的阈值。 我个人使用another算法的非极大值抑制

您的代码将变为:

import numpy as np
import cv2

img = cv2.imread('Ob.png',cv2.IMREAD_GRAYSCALE)

dx,dy = cv2.spatialGradient(img,ksize=5)

mag = cv2.magnitude(dx.astype(np.float32),dy.astype(np.float32))

se = cv2.ximgproc_StructuredEdgeDetection()

ori = se.computeOrientation(mag)

edges_without_nms = se.edgesNms(mag,ori)

希望对你有所帮助

您的代码中发生的事情很容易解释:

dst1dst2,两个Sobel滤波器的输出,是梯度向量的x和y分量。对于一个给定的像素,梯度向量由 (dst1[i,j], dst2[i,j]) 给出。这个向量可以有任何值,例如 (5.8,-2.1),导致大约 340 度的角度。

接下来,您对这两幅图像进行阈值处理。 Otsu thresholding 将找到一个值,该值将图像很好地分成低强度像素和高强度像素。它们分别被分配了 0 和 255 的值。但首先,您将浮点图像转换为 uint8,将所有负值设置为 0。因此,我们的向量 (5.8,-2.1) 首先转换为 (5,0),然后进行阈值处理,之后它变为 ( 255,0) 或 (0,0) 取决于 5 落在阈值的哪一侧。

因此,我们已将角度为 340 度的矢量转换为角度为 0 度或无法计算的角度(尽管 atan2(0,0) 通常也会产生 0)。

事实上,所有向量都变成了 (0,0)、(0,255)、(255,0) 或 (255,255),这意味着您只会找到 0、45 和 90 度角。

您应该做的是计算幅度和阈值(我不知道 Otsu 是否是此类图像的理想方法)。接下来,仅使用幅度高于阈值的那些像素的角度。

另一种常见的替代方法是使用高斯梯度代替 Sobel。在那里,您可以设置一个平滑(正则化)参数,它可以让您去除或多或少的噪音。我经常看到它实现为高斯模糊,然后是 Sobel 滤波器,尽管对我来说直接使用高斯导数滤波器更有意义。