OpenCV filter2d给出错误的结果

时间:2019-02-19 12:49:12

标签: python numpy opencv image-processing

我目前正在尝试使用自己构建的Laplacian内核过滤图像。但是,与SciPy中的实现相比,使用此内核对输入图像进行过滤时,会产生意外结果。

我构建的拉普拉斯内核应通过以下图像进行验证

1D 2D

用于过滤图像的代码:

im = cv2.imread("test.png",0)
im = im.astype(np.float32)

def lkern(t=1.):
    ax = np.arange(np.round(-5*np.sqrt(t),0),np.round(5*np.sqrt(t),0)+1)
    xx, yy = np.meshgrid(ax, ax)

    kernel = -1/(np.sqrt(2*np.pi*t)*t)*np.exp(-(xx**2+yy**2)/(2*t))+
        (xx**2+yy**2)/(np.sqrt(2*np.pi*t)*t**2)*np.exp(-(xx**2+yy**2)/(2*t))


    return kernel.astype(np.float)

t = 25**2/2
l = lkern(t)

L = cv2.filter2D(im/255,-1,l)

plt.figure()
plt.imshow(L,cmap="gray")
plt.show()

结果

res

与SciPy的ndimage.gaussian_laplace相比,结果应该是

scipy

这是非常不同的,我无法弄清楚该怎么做。

1 个答案:

答案 0 :(得分:2)

OP中的代码似乎采用一维高斯Laplace方程,并使用该方程构造2D径向对称函数。也就是说,沿着内核的任何直径,函数看起来都像一维高斯Laplace。这不是创建2D高斯Laplace的正确方法。

高斯is defined的拉普拉斯(Laplace)是高斯核沿着每个轴的二阶导数之和。也就是说,

LoG = d²/dx² G + d²/dy² G

使用G高斯核。

使用Numpy,您可以按以下方式构造此内核。我正在使用高斯的可分性来降低计算复杂性。

s = 5;
x = np.arange(np.floor(-4*s),np.ceil(4*s)+1)
g = 1/(np.sqrt(2*np.pi)*s)*np.exp(-x**2/(2*s**2))
d2g = (x**2 - s**2)/(s**4) * g
log = g * d2g[:,None] + g[:,None] * d2g

此处的技巧:gd2g是一维函数。 g[:,None]将一维功能转到一边,这样乘法会导致广播,从而产生2D输出。

我以这种方式编写了内核,而不是一口气表示完整的2D方程,因为这会导致代码效率很高:图像f与内核log的卷积可以写成:

conv(f, log) = conv(f, g * d2g[:,None] + g[:,None] * d2g)
             = conv(conv(f, g), d2g[:,None]) + conv(conv(f, g[:,None]), d2g)

也就是说,我们使用一个相对较小的1D内核来计算4个卷积,而不是使用一个较大的2D内核进行一次卷积。请注意,此处的实际顺序无关紧要:

  • 一个应用一维内核g,然后沿另一轴应用一维内核d2g。这两个操作可以相反。
  • 然后重复此过程,更改应用每个操作的轴。
  • 最后一个将两个结果相加。

(可以在我写cv2.filter2D的地方使用convconv仅表示任何卷积函数,但是像filter2D这样的相关函数就可以了,因为内核是全部对称。)