设置
我目前正在尝试使用sobel滤波器计算图像梯度.
起初,我通过以下方式使用scipy.ndimage.sobelfunction:
sx = ndimage.sobel(im, axis=0,mode="constant")
sy = ndimage.sobel(im, axis=1,mode="constant")
sobel = np.hypot(sx,sy)
sobel *= 255 / np.max(sobel)
但是,这仅将(3×3)sobel滤镜应用于我的图像,但是我想尝试更大的滤镜.因此,我尝试使用numpy和scipy.signal计算图像梯度.首先,我再次尝试了(3×3)过滤器.
filter_x = np.array([[-1,0,1],[-2,0,2],[-1,0,1]], dtype=np.float)
filter_y = np.array([[1,2,1], [0,0,0], [-1,-2,-1]], dtype = np.float)
sx = signal.convolve2d(im,filter_x,mode="same",boundary="symm", fillvalue=0)
sy = signal.convolve2d(im,filter_y,mode="same",boundary="symm", fillvalue=0)
sobel = np.hypot(sx,sy)
sobel *= 255 / np.max(sobel)
如this帖子中的建议.
问题
不幸的是,这两种方法导致了完全不同的结果,这已经在this问题中提到.
因此,我进行了更深入的研究,发现scipy.ndimage.sobel使用relatede1d函数而不是convolve2d或任何类似的(source code).不幸的是,由于相关功能已隐藏在我的conda环境的site-packages文件夹中的_nd_image.pyd编译文件.所以这是我的问题:
题
有谁明确地知道,correlate1d到底在计算什么,它与convolve2d在什么方面具有可比性?
编辑
正如在Florian Drawitsch的回答中已经提到的那样,人们应该能够通过相关性代替卷积.但话又说回来,这些不同的结果如何出现?
解决方法:
从方法名称correlate1d和convolve2d来看,我强烈怀疑前者计算相关性,而后者计算卷积.有什么不同?
一般来说,信号f与内核g的卷积涉及在操作之前翻转内核:f * g(-t)
相反,在不翻转内核的情况下执行信号f与内核g的相关:f * g(t)
因此,与使用相关的结果相比,使用卷积应用方向性边缘检测内核(如sobel内核)应该会导致边缘倒置.让我们在代码中测试一下:
import numpy as np
from scipy import signal
from PIL import Image
from matplotlib import pyplot as plt
img = Image.open('lena.png')
plt.imshow(img)
首先,让我们定义一个sobel边缘检测内核:
g = np.asarray([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])
现在让我们首先使用sicpy的signal.convolve2d将图像与内核进行卷积
img_convolved = signal.convolve2d(img, g)
plt.imshow(img_convolved, cmap='gray')
…并放大边缘:
plt.imshow(img_convolved[100:150,100:150], cmap='gray')
现在,让我们使用sicpy的signal.correlate2d将图像与内核相关联
img_correlated = signal.correlate2d(img, g)
plt.imshow(img_correlated, cmap='gray')
…并放大边缘:
plt.imshow(img_correlated[100:150,100:150], cmap='gray')
最后,让我们将相关结果与如果使用翻转内核进行卷积会发生的情况进行比较:
img_convolved_flipped = signal.convolve2d(img, np.fliplr(g))
plt.imshow(img_convolved, cmap='gray')
…并放大边缘:
plt.imshow(img_convolved_flipped[100:150,100:150], cmap='gray')
因此,scipy的signal.correlate2d(img,g)等同于signal.convolve2d(img,np.fliplr(g))
编辑(对2D代码示例的说明):
请注意,在2D情况下,信号f与内核g的卷积涉及围绕两个基本轴f * g(-t,-u)翻转内核.
因此,在我的代码中,我实际上应该将过滤器翻转两次:np.flipud(np.fliplr(g)).我已经省略了这个,因为对于垂直对称的sobel滤波器不是必需的,但是请记住,这是一个特例.