0

我正在尝试使用scipy.ndimage.convolve计算二维字段A的拉普拉斯算子。

stencil = numpy.array([[0, 1, 0],[1, -4, 1], [0, 1, 0]])
scipy.ndimage.convolve(A, stencil, mode='wrap')

不过,这似乎并没有给我正确的答案。有什么想法会出错,或者有更好的方法来计算 numpy 中的拉普拉斯算子吗?

4

4 回答 4

2

我有另一个想法:您是否考虑过您的模板,为了近似拉普拉斯算子,应该除以 step**2,其中 step 是您网格的步长?只有这样,您才能将 ndimage.convolve 结果与分析结果进行比较。

事实上,使用高斯,我得到的结果表明 ndimage.convolve 工作得很好:

from scipy import ndimage

stencil = numpy.array([[0, 1, 0],[1, -4, 1], [0, 1, 0]])
x = linspace(-10, 10, 100)
y = linspace(-10, 10, 100)
xx, yy = meshgrid(x, y)
image = exp(-xx**2-yy**2)  # Standard deviation in x or y: 1/sqrt(2)

laplaced = ndimage.convolve(image, stencil)/(x[1]-x[0])**2  # stencil from original post
expected_result = -4*image + 8*(xx**2+yy**2)*image  # Very close to laplaced, in most points!
于 2009-11-20T14:30:14.893 回答
2

5年前,我想知道还有人在乎...

我认为这是因为卷积方法只是一个近似值,模板基本上是通过有限离散微分来近似二阶导数。增量越小,数值越接近。

我根据其他人的信息做了一些测试。下面是代码和结果图:

import numpy
import scipy.ndimage.filters as filters
import scipy.signal as signal
import matplotlib.pyplot as plt


stencil=numpy.array([[0,1,0],[1,-4,1],[0,1,0]])

fig=plt.figure(figsize=(10,10),dpi=100)

for ii,jj in enumerate([10,100,1000,10000]):

    x=numpy.linspace(-5,5,jj)
    xx,yy=numpy.meshgrid(x,x)
    step=x[1]-x[0]

    image=numpy.exp(-xx**2-yy**2)

    lap1=filters.laplace(image)/step**2
    #lap2=filters.convolve(image,stencil,mode='wrap')/step**2
    #lap3=signal.convolve2d(image,stencil,mode='same')/step**2
    lap4=4*image*(xx**2+yy**2)-4*image

    ax=fig.add_subplot(2,2,ii+1)
    img=ax.imshow(lap1-lap4)
    ax.set_title('stencil - analytical (dx=%.4f)' %step)
    plt.colorbar(img)

fig.tight_layout()
plt.show()

在此处输入图像描述

,和都给出了非常接近的结果(事实上filters.laplace(),如果你查看 filters.laplace() 的源代码,它本质上与卷积模板内核做同样的事情),所以我只包括一个。请注意,以上所有内容均未除以步长的平方。filters.convolve()signal.convolve2d()filters.laplace()

该图显示,增量步长越小,越接近解析解(即4z(x^2+y^2)-4z)。

于 2015-10-14T16:23:03.743 回答
1

您是否尝试过另一个拉普拉斯卷积核,例如[[1,1,1][1,-8,1][1,1,1]]

于 2009-11-19T17:13:11.683 回答
0

我试过你的例子,它确实适用于我机器上最新的 SciPy。

我建议您进行绘图image-ndimage.convolve(…)以查看卷积如何改变您的图像。

例子:

image = vstack(arange(-10, 10)**2 for _ in range(20))
ndimage.convolve(image, stencil, mode='wrap')

产量

array([[-38,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,...)

这是完全正确的(x**2 的二阶导数是 2)——除了左边界。

于 2009-11-19T22:01:10.900 回答