大津阈值和图像梯度方向

时间:2018-09-29 19:57:29

标签: python opencv image-processing opencv-python

我想对图像渐变应用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)

2 个答案:

答案 0 :(得分:3)

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

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。在那里,您可以设置平滑(正则化)参数,该参数可以消除或多或少的噪声。我经常看到这是在高斯模糊之后加上Sobel滤波器实现的,尽管直接使用高斯导数滤波器对我来说更有意义。

答案 1 :(得分:0)

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

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

您将由于梯度滤镜而命名为“噪声”的东西实际上称为非最大值。 通常,诸如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)

希望对您有帮助。