Python:使用GPU进行双三次插值

3
在Python中,我使用scipy.ndimage.zoom对图像执行双三次插值,但发现在上采样时速度太慢。我想用一些支持GPU的其他Python库来替换它,但不幸的是我找不到一个可用于Python的库。
NVIDIA提供了一个很好的示例,它完全实现了C/C++中的双三次插值。是否有已知的等效CUDA Python示例/库,我们可以直接使用并替换scipy.ndimage.zoom
我在网上进行了一些搜索,但无法找到在Python中使用GPU进行双三次插值的方法。因此,我认为没有太多可用的答案,这可能导致主观性的答案和垃圾邮件。
1个回答

3

虽然不是GPU(而是尝试利用线程和CPU的矢量单元),但pyvips比scipy快得多,您可以进行测试。

我进行了基准测试:

import sys
import time

import scipy.ndimage
import pyvips

scale = 10
n_loops = 10

start = time.time()
test_image = scipy.ndimage.imread(sys.argv[1])
for i in range(0, n_loops):
    result = scipy.ndimage.interpolation.zoom(test_image, scale)
end = time.time()

print 'scipy took', end - start

start = time.time()
test_image = pyvips.Image.new_from_file(sys.argv[1])
for i in range(0, n_loops):
    result = test_image.resize(scale).write_to_memory()
end = time.time()

print 'pyvips took', end - start

# transform with both libraries to compare results

ndi = scipy.ndimage.imread(sys.argv[1])
result = scipy.ndimage.interpolation.zoom(ndi, scale)
scipy.misc.imsave('ndi.tif', result)

im = pyvips.Image.new_from_file(sys.argv[1], access='sequential')
result = im.resize(scale)
result.write_to_file('pyvips.tif')

默认都是双三次插值。pyvips是一个懒惰库,所以你需要在结尾处使用额外的write_to_memory()来生成内存数组。

在这台四核/八线程的Ubuntu 17.10桌面上,使用所有库的预装版本和一个512x512单色版本的“lena”测试图像,我看到:

$ python zoom.py ~/pics/lena.png 
scipy took 15.6309859753
pyvips took 1.36838102341

一个GPU的升频器显然会更快,但也许pyvips已经足够快了?

如果你比较这两个输出图像,你会发现scipy的那个向上移动了一点点。你可以用一个非常小的输入图像更清楚地看到正在发生的事情,例如这个3x3像素的图像:

3x3 pixel test image

当被scipy放大20倍和pyvips变成:

20x upsize with scipy and pyvips

这使我感到困惑。此外,它们明显使用不同的内核,这也很奇怪。


我尝试使用 pyvips 并将上述的 big 转换为 ndarray,代码如下:numpy.ndarray(buffer=big.write_to_memory(), dtype=numpy.uint8, shape=[big.height, big.width, big.bands])。然后我尝试将图像与 scipy.ndimage.zoom(image, (4, 4, 1.0), order=3) 进行比较,并发现由于某种原因像素有些偏移。我对 pyvips 不太熟悉,请告诉我是否正确地使用了 pyvips - chesschi
我在桌面机上更新了时间,并添加了输出的比较。我认为pyvips在这里可能更准确。我想知道内核的差异,我会查看源代码。 - jcupitt
非常感谢您的回复。是的,我在我的测试图像中也看到了类似的上移效应。我确实查看了 pyvips 的文档,但它并没有解释 resize 是如何实现的。另一方面,在使用 scipy 时,输入会在插值之前预先使用样条滤波器进行过滤。这在 pyvips 中可能会有不同的处理方式。 - chesschi
libvips的缩放只是调用vips_affine进行上采样,参数设置为中心约定双三次插值和边缘扩展。双三次插值器使用4x4的模板(自适应的双三次降采样)。我将看一下spline_filter,也许这就是区别所在。 - jcupitt
GPU只能执行线性插值操作吗? - KeyC0de
你可以在着色器中实现双三次插值。 - jcupitt

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