为什么图像卷积算子的方向不直观?

时间:2014-11-09 10:54:00

标签: python image-processing scipy imagefilter

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

例如,Sobel运营商: http://en.wikipedia.org/wiki/Sobel_operator

右侧为阳性,左侧为Gx阴性,而上部为Gy阳性。

我不是图像处理方面的专家。但我认为大多数人从图像的左上角计算像素。由于我们需要在卷积过程中“翻转”内核,为什么在定义运算符时Gx不是一个镜像更好的规则?

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

1 个答案:

答案 0 :(得分:2)

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

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

这是一个并排比较,以显示差异。对于输入,我们在维基百科文章中使用自行车图像: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()

请注意,值会被有效翻转。

enter image description here


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

例如,numpy.gradientscipy.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()

enter image description here

因此,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()

enter image description here

在这种情况下使用哪种约定并不重要,因为所有重要的是输入渐变的绝对值。

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