Otsu阈值和图像渐变方向



我想将 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)

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

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

接下来,对这两个图像进行阈值设置阈值。Otsu阈值将找到一个值,该值将图像很好地分为低强度像素和高强度像素。它们分别分配了 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滤波器,尽管直接使用高斯导数滤波器对我来说更有意义。

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

我认为在 Sobel 处理期间让它做会更有效率。 这只是我的观点。

由于梯度滤波器,您命名为"噪声"的东西实际上称为非最大值。 通常,诸如Canny之类的算法确实包括在Sobel过滤之后对其进行阈值设置。 这种方法的不便之处在于找到适当的阈值。 就个人而言,我使用另一种算法的非极大值抑制。

您的代码将变为:

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)

我希望它对你有所帮助。

最新更新