【问题标题】:Why the orientation of image convolution operators are not intuitive?为什么图像卷积算子的方向不直观?
【发布时间】:2015-01-05 18:55:02
【问题描述】:

感谢您阅读本文,请原谅我的英语不好,因为我不是母语人士。

例如,Sobel 算子: http://en.wikipedia.org/wiki/Sobel_operator

Gx右侧为正,左侧为负,Gy为正。

我不是图像处理专家。但我想大多数人从图像的左上角开始计算像素。既然我们在卷积的过程中需要“翻转”内核,为什么在定义算子时为了更好的规律性,Gx不是镜像的呢?

我知道从技术上讲这不是编程问题。但它与编程有关。 例如,python 的scipy.ndimage 提供了sobel 函数。该函数使用左列为正,右列为负的内核。它不同于我能找到的所有关于图像处理的材料(包括维基百科的文章)。有什么特殊原因导致实际实现与数学定义不同?

【问题讨论】:

  • 您的编程问题是什么?
  • 该链接没有说明他们使用什么 Y 约定。无论方向约定如何,都使用 F(X+1,Y)-F(X-1,Y) 和 F(X,Y+1)-F(X,Y-1)。
  • @Taosique 很抱歉让您感到困惑。我在 SciPy 中添加了一个示例来更清楚地描述我的问题。
  • @JoeKington 谢谢。这就是我的观点。我喜欢 SciPy 的方式。

标签: python image-processing scipy imagefilter


【解决方案1】:

首先,让我稍微改一下你的问题:

为什么scipy.ndimage 的 Sobel 运算符版本似乎与 Wikipedia 上给出的定义相反?

这是一个并排比较以显示差异。对于输入,我们使用维基百科文章中的自行车图片:http://en.wikipedia.org/wiki/File:Bikesgray.jpg

import matplotlib.pyplot as plt
import numpy as np
import scipy.ndimage as ndimage

# Note that if we leave this as unsigned integers  we'll have problems with
# underflow anywhere the gradient is negative. Therefore, we'll cast as floats.
z = ndimage.imread('Bikesgray.jpg').astype(float)

# Wikipedia Definition of the x-direction Sobel operator...
kernel = np.array([[-1, 0, 1],
                   [-2, 0, 2],
                   [-1, 0, 1]], dtype=float)
sobel_wiki = ndimage.convolve(z, kernel)

# Scipy.ndimage version of the x-direction Sobel operator...
sobel_scipy = ndimage.sobel(z, axis=1)

fig, axes = plt.subplots(figsize=(6, 15), nrows=3)
axes[0].set(title='Original')
axes[0].imshow(z, interpolation='none', cmap='gray')

axes[1].set(title='Wikipedia Definition')
axes[1].imshow(sobel_wiki, interpolation='none', cmap='gray')

axes[2].set(title='Scipy.ndimage Definition')
axes[2].imshow(sobel_scipy, interpolation='none', cmap='gray')

plt.show()

请注意,这些值被有效地翻转了。


这背后的逻辑是 Sobel 滤波器基本上是一个梯度算子(numpy.gradient 等价于与[1, 0, -1] 的卷积,除了边缘)。维基百科中给出的定义给出了梯度的数学定义的否定。

例如,numpy.gradient 给出与scipy.ndimage 的 Sobel 过滤器相似的结果:

import matplotlib.pyplot as plt
import numpy as np
import scipy.ndimage as ndimage

z = ndimage.imread('/home/jofer/Bikesgray.jpg').astype(float)

sobel = ndimage.sobel(z, 1)
gradient_y, gradient_x = np.gradient(z)

fig, axes = plt.subplots(ncols=2, figsize=(12, 5))
axes[0].imshow(sobel, interpolation='none', cmap='gray')
axes[0].set(title="Scipy's Sobel")

axes[1].imshow(gradient_x, interpolation='none', cmap='gray')
axes[1].set(title="Numpy's Gradient")

plt.show()

因此,scipy.ndimage 使用的约定与我们对数学梯度的期望一致。


快速旁注:通常所说的“sobel 滤波器”实际上是从两个 sobel 滤波器沿不同轴计算得出的梯度幅度。在scipy.ndimage 中,您可以这样计算:

import matplotlib.pyplot as plt
import scipy.ndimage as ndimage

z = ndimage.imread('/home/jofer/Bikesgray.jpg').astype(float)

sobel = ndimage.generic_gradient_magnitude(z, ndimage.sobel)

fig, ax = plt.subplots()
ax.imshow(sobel, interpolation='none', cmap='gray')
plt.show()

在这种情况下使用哪种约定也无关紧要,因为重要的是输入梯度的绝对值。

无论如何,对于大多数用例,具有可调节窗口的更平滑的梯度过滤器(例如ndimage.gaussian_gradient_magnitude)是边缘检测的更好选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-01
    • 2016-11-11
    • 2018-08-10
    • 1970-01-01
    • 2016-12-22
    • 2011-09-25
    • 2021-10-15
    相关资源
    最近更新 更多