【问题标题】:Otsu Thresholding and Image gradient orientation大津阈值和图像梯度方向
【发布时间】:2018-09-29 19:57:28
【问题描述】:

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

【问题讨论】:

  • 您确实理解阈值意味着将值设置为 0 或 1,对吗?现在你所有的梯度向量都是 [0,0]、[0,1]、[1,1]、[1,0] 等。当然它们的方向被量化到最接近的 45 度。阈值化并不是为了消除噪音。请尝试平滑!
  • @Cris Luengo 对此深表歉意,但请检查什么是 sobel 过滤器 (en.wikipedia.org/wiki/Sobel_operator) 以及 OpenCV 的阈值标志对应的内容 (docs.opencv.org/master/d7/d4d/tutorial_py_thresholding.html)
  • @John_Sharp1318:你为什么给我这些链接?我不确定为什么我写的不是对 OP 遇到的问题的清晰解释。
  • 第二个链接 opencv 阈值函数 如果未使用标志 THRESH_TRUNC 如果使用标志 THRESH_TRUNC 则返回值介于 0-255 之间的矩阵,则范围变为 0 - 图像的值。它也写在文档中。之所以喜欢它,是因为 opencv 本身不支持布尔值,它们被转换为 uint8 矩阵。基本上阈值返回一个掩码。第一个链接是因为您编写的蒙版不对应于任何渐变运算符,但阅读您的答案我知道它们不是渐变蒙版而是方向一个对不起。
  • @John_Sharp1318:啊,好的,所以 OpenCV 使用 0 和 255,而不是 0 和 1。我总是忘记这一点,谢谢。我已经确定了答案。

标签: python opencv image-processing opencv-python


【解决方案1】:

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

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 过滤器,尽管直接使用高斯导数过滤器对我来说更有意义。

【讨论】:

    【解决方案2】:

    如果我可以,为什么你要做的第一件事是将数据转换为 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)
    

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-12
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多