2013-02-08 135 views
14

我想尝试编写一个简单的函数来平滑输入的图像。我试图用Image和numpy库来做到这一点。我正在考虑使用卷积蒙版将是一个解决这个问题的方法,并且我知道numpy具有内置的卷积函数。Python中的图像平滑

如何使用numpy.convolve来平滑图像?

+2

你可能需要一个二维卷积,如'scipy.signal.convolve2d' – wim

回答

16

不错的问题! 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() 

enter image description here

+0

你知不知道'scipy.signals.convolve2d'和'scipy.ndimage.convolve'之间是否有真正的区别,因为它们看起来都是用同样的东西做的,只是参数略有不同。 – tacaswell

+0

我认为后者被推广到更高的维度,前者被指定为2d阵列。虽然通常不想将颜色通道“涂抹”到彼此之中,但使用3D内核来处理图像会很奇怪。 – wim

+0

对不起,愚蠢的问题后,我在我的答案中评论说,“convolve”进入更高维度.....认为是时候睡觉了。 – tacaswell

16

你想看看ndimage,这是scipy模块。它有许多过滤器 作为函数设置,以及用于卷积任意内核的漂亮包装。

例如,

img_gaus = ndimage.filters.gaussian_filter(img, 2, mode='nearest') 

用的2

如果你想卷积任意内核西格玛高斯卷积你的形象,说一个跨

k = np.array([[0, 1, 0], 
       [1, 1, 1], 
       [0, 1, 0]]) 

img2 = ndimage.convolve(img, k, mode='constant') 

这些功能对于更高维度也是很好的,所以你可以使用几乎相同的代码(只是扩展你的内核的维度)来平滑更高维度的数据。

modecval参数控制卷积如何处理图像边缘的像素(对于边缘像素,内核需要查看的一半区域不存在,因此您需要选取用来填充图像的东西)。

4

如果你不想使用SciPy的,你有三种选择:

1)你可以使用卷积定理与傅里叶变换相结合,因为numpy的具有2D FFT。 2)你可以使用一个可分离的内核,然后你可以在平坦的数组上进行两个一维卷积,一个在x方向,另一个在y方向(ravel the transpose),这样会给出相同的结果结果作为2D卷积。

3)如果你有一个小内核,说,3x3的,它很容易只是写出来的卷积乘法和款项。这听起来像一个麻烦,但它并没有那么糟糕。

如果你想使用SciPy的,你可以使用ngimage,作为tcaswell建议。 scipy也有convolve2d。