Python-pillow中使用大于5x5的卷积核进行卷积

3
我想在Python-Pillow中使用简单卷积核对图像进行滤波。然而,为了获得最佳结果,我需要一个9x9的卷积核。在pillow中,使用ImageFilter.Kernel和内置的filter()方法时,最多只能使用5x5的卷积核,这是不可能的not possible
除了实现自己的卷积代码外,是否有一种方法可以使用大于5x5的卷积核来过滤/卷积图像?

你能展示一下为什么不可能吗?只是为了完整性?或者尝试一些带有错误的代码? - User
2
你是否只限于使用PIL?你考虑过使用OpenCV或者scipy吗? - rayryeng
1
@用户:文档中明确说明了。此外,使用更大的内核调用filter()会引发“坏内核大小”ValueError。 - jpfender
1
我没有PIL的经验,但我很惊讶你不能使用大于5x5的卷积核。在这种情况下,如果你正在使用scipy,请看一下ndimage包中的convolve:http://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.ndimage.filters.convolve.html。你可以使用[`scipy.imread`](http://docs.scipy.org/doc/scipy-0.13.0/reference/generated/scipy.ndimage.imread.html)加载图像,进行卷积,然后使用[`Image.fromArray`](http://pillow.readthedocs.org/en/latest/reference/Image.html#PIL.Image.fromarray)将其转换为PIL Image对象。 - rayryeng
@rayryeng 是的,那个方法完美地解决了我的问题!将其转换回PIL图像仅在学术上有用,因为我可以在我的应用程序中直接使用scipy数组,但是知道原则上这是可能的很好。谢谢! - jpfender
显示剩余3条评论
2个回答

3

我很惊讶地发现PIL没有超过5 x 5内核的支持。因此,最好看看其他Python包,例如OpenCVscipy...为了节省时间,让我们使用scipy。尽管OpenCV非常强大,但配置起来很麻烦。

我建议使用scipyndimage包中加载您的图像,并使用imread函数将其转换为numpy.ndarray,然后用您的卷积核对图像进行卷积操作,完成后再转换回PIL图像。使用ndimage包中的convolve函数进行卷积,在使用Image.fromArray函数将其转换回PIL图像时,它支持将numpy.ndarray转换为PIL格式,非常方便。假设您使用的是9x9平均滤波器,则代码类似于这样:
# 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 是另一个选择,如果您没有使用 pillow、numpy 或 scipy 的限制。它的速度更快,需要的内存更少,特别是对于较大的图像。在某些基准测试中,它甚至能够击败 opencv。

我在这台笔记本电脑上进行了尝试:

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

一张10k x 10k像素的黑白jpg图片在2015年的i5笔记本电脑上需要大约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的内存。

这是浮点卷积。你可以像这样将其转换为整型精度:

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秒。


谢谢您提供这个较新的答案! - rayryeng
谢谢!虽然libvips Python绑定已经被重写,但我已将其更新到最新版本。 - jcupitt
谢谢!好奇。你有和scikit-image进行比较吗?对于那方面的基准测试感到好奇。 - rayryeng
是的,没错。虽然我在基准测试中没有看到它,但我确实喜欢这个库的开发方式。 - rayryeng
好的,已添加scikit-image。在我的机器上,它比pyvips慢了29倍。也许我犯了什么可怕的错误:( - jcupitt
不,我认为那是正确的。我忘记了scikit-image没有通用卷积函数。他们不想取代scipy而是补充它。我们就这样吧。 - rayryeng

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