我想尝试编写一个简单的函数来平滑输入的图像。我试图使用 Image 和 numpy 库来做到这一点。我在想使用卷积掩码将是解决这个问题的一种方法,我知道 numpy 内置了一个卷积函数。
如何使用numpy.convolve平滑图像?
我想尝试编写一个简单的函数来平滑输入的图像。我试图使用 Image 和 numpy 库来做到这一点。我在想使用卷积掩码将是解决这个问题的一种方法,我知道 numpy 内置了一个卷积函数。
如何使用numpy.convolve平滑图像?
好问题! tcaswell在这里的帖子是一个很好的建议,但是您不会通过这种方式学到很多东西,因为 scipy 正在为您完成所有工作!由于您的问题说您想尝试编写函数,我将向您展示一种更粗略和基本的手动方式,希望您能更好地理解卷积等背后的数学,然后您可以改进用你自己的想法和努力吧!
注意:使用不同形状/大小的内核,您会得到不同的结果,高斯是常用的方法,但您可以尝试其他一些有趣的方法(余弦、三角形等!)。这个是我现场编的,我觉得是一种金字塔形的。
import scipy.signal
import numpy as np
import matplotlib.pyplot as plt
im = plt.imread('example.jpg')
im /= 255. # normalise to 0-1, it's easier to work in float space
# make some kind of kernel, there are many ways to do this...
t = 1 - np.abs(np.linspace(-1, 1, 21))
kernel = t.reshape(21, 1) * t.reshape(1, 21)
kernel /= kernel.sum() # kernel should sum to 1! :)
# convolve 2d the kernel with each channel
r = scipy.signal.convolve2d(im[:,:,0], kernel, mode='same')
g = scipy.signal.convolve2d(im[:,:,1], kernel, mode='same')
b = scipy.signal.convolve2d(im[:,:,2], kernel, mode='same')
# stack the channels back into a 8-bit colour depth image and plot it
im_out = np.dstack([r, g, b])
im_out = (im_out * 255).astype(np.uint8)
plt.subplot(2,1,1)
plt.imshow(im)
plt.subplot(2,1,2)
plt.imshow(im_out)
plt.show()
你想看看ndimage
,这是一个模块scipy
。它有许多过滤器都设置为函数,以及用于卷积任意内核的漂亮包装器。
例如,
img_gaus = ndimage.filters.gaussian_filter(img, 2, mode='nearest')
将您的图像与 sigma 为 2 的高斯卷积。
如果你想卷积一个任意内核,比如说一个交叉
k = np.array([[0, 1, 0],
[1, 1, 1],
[0, 1, 0]])
img2 = ndimage.convolve(img, k, mode='constant')
这些函数也适用于更高维度,因此您可以使用几乎相同的代码(只是扩大内核的维度)来平滑更高维度的数据。
和参数控制卷积如何处理图像边缘的像素(对于边缘上的像素,内核需要查看的一半区域不存在,因此您需要选择一些东西来填充mode
图像cval
和)。
如果你不想使用 scipy,你有三个选择:
1)您可以将卷积定理与傅里叶变换结合使用,因为 numpy 具有 2D FFT。
2)您可以使用可分离的内核,然后您可以在展平的阵列上进行两个一维卷积,一个在 x 方向,另一个在 y 方向(拉开转置),这将得到与 2D 相同的结果卷积。
3)如果你有一个小内核,比如 3x3,只需将卷积写成乘法和求和就很容易了。这听起来很麻烦,但还不错。
如果你确实想使用 scipy,你可以使用 ngimage,就像 tcaswell 建议的那样。scipy 也有 convolve2d。