【问题标题】:Convolution with kernel size larger than 5x5 in python-pillowpython-pillow中内核大小大于5x5的卷积
【发布时间】:2015-10-04 14:44:27
【问题描述】:

我想在 python-pillow 中使用简单的卷积核过滤图像。但是,为了达到最佳效果,我需要一个 9x9 内核。这是枕头中的not possible,至少在使用ImageFilter.Kernel 和内置的filter() 方法时,它们仅限于5x5 内核。

没有实现我自己的卷积代码,有没有办法过滤/卷积内核大小大于 5x5 的图像?

【问题讨论】:

  • 你能说明为什么不可能吗? - 只是为了完整性?或者一些代码尝试出错?
  • 您是否仅限于使用 PIL?您是否考虑过使用 OpenCV 或 scipy
  • @User:文档中明确说明了这一点。此外,使用更大的内核调用 filter() 会引发“错误的内核大小”ValueError。
  • @rayryeng 不,我更喜欢使用 PIL 的解决方案,因为它非常简单和干净,并且完全符合我的需求。但我目前正在研究 scipy。
  • 我在 PIL 方面没有经验,但我很惊讶地发现您不能与任何 > 5 x 5 的东西进行卷积。在这种情况下,如果您正在查看 scipy,看看convolve 这是ndimage 包的一部分:docs.scipy.org/doc/scipy-0.15.1/reference/generated/…。您可以使用scipy.imread 加载图像,进行卷积,然后使用Image.fromArray 转换为PIL Image 对象

标签: python image-processing filtering convolution pillow


【解决方案1】:

看到 PIL 不支持超过 5 x 5 的内核,我感到非常惊讶。因此,谨慎的做法是查看其他 Python 包,例如 OpenCVscipy... 为了节省时间,我们使用 scipy。尽管 OpenCV 非常强大,但配置起来很麻烦。

我建议使用scipy 使用ndimage 包中的imread 加载映像,将映像与内核进行卷积,然后在完成后转换为PIL 映像。使用ndimage 包中的convolve,然后通过Image.fromArray 转换回PIL 图像。它确实支持转换 numpy.ndarray(这是您使用 scipy.ndimage.imread 时加载的内容),这很棒。

类似这样,假设一个 9 x 9 平均滤波器:

# Import relevant packages
import numpy as np
from scipy import ndimage
from PIL import Image

# Read in image - change filename to whatever you want
img = ndimage.imread('image.jpg')

# Create kernel
ker = (1/81.0)*np.ones((9,9))

# Convolve
out = ndimage.convolve(img, ker)

# Convert back to PIL image
out = Image.fromArray(out, 'RGB')

【讨论】:

    【解决方案2】:

    pyvips 是另一种选择,如果您不依赖于枕头、numpy 或 scipy。它的速度要快得多,并且需要的内存要少得多,尤其是对于较大的图像。它也会击败 opencv,at least on some benchmarks

    我在这台笔记本电脑上试过:

    import sys
    import numpy as np
    from scipy import ndimage
    from PIL import Image
    
    img = ndimage.imread(sys.argv[1])
    ker = (1 / 81.0) * np.ones((9, 9))
    out = ndimage.convolve(img, ker)
    out = Image.fromarray(out)
    out.save(sys.argv[2])
    

    我可以这样运行:

    $ /usr/bin/time -f %M:%e ./try257.py ~/pics/wtc-mono.jpg x.jpg
    300352:22.47
    

    因此,在 2015 i5 笔记本电脑上制作 10k x 10k 像素的单声道 jpg 大约需要 22 秒,并且需要 300mb 的峰值内存。

    在 pyvips 中是:

    import sys
    import pyvips
    
    im = pyvips.Image.new_from_file(sys.argv[1], access="sequential")
    size = 9
    kernel = size * [size * [1.0 / (size * size)]]
    im = im.conv(kernel)
    im.write_to_file(sys.argv[2])
    

    我明白了:

    $ /usr/bin/time -f %M:%e ./try258.py ~/pics/wtc-mono.jpg x.jpg
    44336:4.76
    

    大约 5 秒和 45mb 的内存。

    这是一个浮点卷积。您可以像这样将其交换为 int 精度:

    im = im.conv(kernel, precision="integer")
    

    我明白了:

    $ /usr/bin/time -f %M:%e ./try258.py ~/pics/wtc-mono.jpg x.jpg
    44888:1.79
    

    1.8 秒。

    【讨论】:

    • 感谢这个更新的答案!
    • 谢谢!尽管此后 libvips Python 绑定已被重写。我已经更新到最新版本了。
    • 谢谢!好奇的。您是否与 scikit-image 进行了比较?很好奇基准是什么。
    • 是的,没错。我没有在基准测试中看到它,但我确实喜欢这个库的开发方式
    • 好的,添加了 scikit-image。在我的机器上进行的测试中,它比 pyvips 慢 29 倍。也许我犯了一些可怕的错误:(
    猜你喜欢
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-12
    • 2019-03-30
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多