python-pillow 中内核大小大于 5x5 的卷积

Convolution with kernel size larger than 5x5 in python-pillow

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

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

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

我建议使用 scipy 来加载带有 imread from the ndimage package, convolve the image with your kernel, then convert to a PIL image when you're done. Use convolve from the ndimage package, then convert back to a PIL image by Image.fromArray 的图像。它确实支持转换 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')

pyvips is another option, if you're not tied to pillow, numpy or scipy. It's quite a bit faster and needs a lot less memory, especially for larger images. It'll beat opencv too, 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 秒。