【问题标题】:Image smoothing in PythonPython中的图像平滑
【发布时间】:2013-01-23 19:47:32
【问题描述】:

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

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

【问题讨论】:

  • 你可能需要一个二维卷积,例如scipy.signal.convolve2d

标签: python numpy image-processing smoothing


【解决方案1】:

好问题! 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()

【讨论】:

  • 您知道scipy.signals.convolve2dscipy.ndimage.convolve 之间是否存在真正的区别,因为它们似乎都在做同样的事情,只是参数略有不同。
  • 我认为后者被推广到更高的维度,前者被指定为二维数组。不过,您通常不希望将颜色通道“涂抹”到彼此中,因此将 3d 内核用于图像会很奇怪。
  • 对不起,愚蠢的问题,因为我在回答中评论了convolve 进入更高的维度......认为是时候睡觉了。
  • 感谢代码,但是我遇到了一些问题。当我运行代码时,输​​出图像旋转了 180 度,并且出现了黑色斑点。这会是由于内核造成的吗?见这里dropbox.com/s/jqqezj0sqddrusc/output.png
  • 太好了,我明白了!我不得不评论 im /= 255 并把 im_out * 255 拿出来只是 im_out.astype(np.uint8) 你的帮助非常宝贵,非常感谢!
【解决方案2】:

你想看看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')

这些函数也适用于更高维度,因此您可以使用几乎相同的代码(只是扩大内核的维度)来平滑更高维度的数据。

modecval 参数控制卷积如何处理图像边缘的像素(对于边缘上的像素,内核需要查看的一半区域不存在,所以你需要选择一些东西来填充你的图像)。

【讨论】:

    【解决方案3】:

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

    1) 您可以将卷积定理与傅里叶变换结合使用,因为 numpy 具有 2D FFT。

    2) 你可以使用一个可分离的内核,然后你可以在展平的数组上做两个一维卷积,一个在 x 方向,另一个在 y 方向(解开转置),这将得到相同的结果作为二维卷积。

    3) 如果你有一个小内核,比如 3x3,只需将卷积写成乘法和求和就很容易了。这听起来很麻烦,但还不错。

    如果您确实想使用 scipy,您可以使用 ngimage,正如 tcaswell 建议的那样。 scipy 也有 convolve2d。

    【讨论】:

      猜你喜欢
      • 2014-11-18
      • 1970-01-01
      • 2013-06-06
      • 2011-09-11
      • 1970-01-01
      • 2013-08-17
      • 1970-01-01
      • 2017-11-28
      • 2012-09-07
      相关资源
      最近更新 更多