Python中的图像平滑处理

15

我想尝试编写一个简单的函数来平滑输入的图像。我尝试使用Image和numpy库来实现这一点。我认为使用卷积掩码是解决这个问题的方法,而且我知道numpy内置了convolve函数。

我该如何使用numpy.convolve来平滑一个图像?


2
你可能需要进行2D卷积,例如 scipy.signal.convolve2d - wim
3个回答

19
很好的问题!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


谢谢提供代码,但是我遇到了一些问题。当我运行代码时,输出的图像被旋转了180度,并且有黑色斑点。这可能是由于内核引起的吗?请看这里https://www.dropbox.com/s/jqqezj0sqddrusc/output.png - Nick
看起来你正在加载一个 .png 文件(而不是像我一样的 .jpg 文件),这些文件在 matplotlib 中的处理方式不同(它们已经是浮点数 0-1)。尝试将 im /= 255. 这行注释掉。 - wim
旋转图像的问题是 matplotlib 较旧版本中的一个错误,要解决这个问题,可以更新到当前的 1.3.x 版本,或者使用 im = np.flipud(plt.imread('example.png')) 再次翻转它。 - wim
谢谢,这解决了旋转问题!我尝试了几个不同的jpg文件,但都没有成功。你认为这与图像plt.subplot(2,1,1)有关吗?该图像总是显示全黑。我链接的图像接近我想要的,除了内部颜色有黑色。再次感谢您的帮助。 - Nick
1
еӨӘеҘҪдәҶпјҢжҲ‘жҳҺзҷҪдәҶпјҒжҲ‘еҝ…йЎ»жіЁйҮҠжҺүim /= 255并е°Ҷim_out * 255жӣҙж”№дёәim_out.astype(np.uint8)пјҢдҪ зҡ„её®еҠ©ж— д»·пјҢйқһеёёж„ҹи°ўпјҒ - Nick
显示剩余4条评论

18
你想查看 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”参数控制卷积如何处理图像边缘的像素(对于边缘上的像素,内核需要查看的区域的一半不存在,因此您需要选择某些东西来填充图像)。

4
如果不想使用scipy,你有三个选择:
1)可以使用卷积定理和傅里叶变换,因为numpy具有2D FFT。
2)可以使用可分离内核,然后在扁平化的数组上进行两个1D卷积,一个在x方向上,另一个在y方向上(ravel the transpose),这将给出与2D卷积相同的结果。
3)如果你有一个小内核,比如3x3,那么写出卷积作为乘法和求和就足够容易了。听起来很麻烦,但并不是那么难。
如果要使用scipy,则可以像tcaswell建议的那样使用ngimage。 scipy还有convolve2d。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接