Numpy数组的快速插值/重采样 - Python

时间:2016-02-13 15:17:03

标签: python numpy scipy interpolation

目前,我已经编写了一些插入管道的Python代码。

传入的数据形状为numpy数组(1,512,19,25)。我使用scipy.ndimage.interpolation.zoom使阵列变形(1,512,38,50)。这可以通过一次调用函数来完成。基本上,它将每个(19,25)的大小调整为大小(38,50)。

稍后在代码中,当数据以另一种方式移动时,不同的数据将再次调整为另一个方向(38,50)到(19,25)。

一切都按实施方式运作,但我发现这确实很慢。例如,我测试了scipy.ndimage.interpolation.zoom函数来调整图像文件的大小,它比Matlab的imresize函数慢。

在Python中有哪些更快的方法?

2 个答案:

答案 0 :(得分:0)

检查https://python-pillow.org/pillow-perf/中的基准

TL; DR:在大多数情况下,Python中最快的方法是使用pillow-simd

答案 1 :(得分:0)

TLDR; 查看Skimage的pyramid_gaussian。在(512,512)的单个图像上,它显示了0.3M倍的加速。 (163 ms / 471 ns = 346072)。 Pillow-SIMDsuper-fast进行重新采样/调整大小,但要求您先卸载PIL Pillow,然后再安装。它使用并行处理(单指令,多数据-SIMD)和更好的算法,例如用顺序盒替换基于卷积的高斯模糊。设置单独的venv后,建议将其用于生产环境。


有多种方式对图像进行上采样和下采样。我将为我使用的方法添加一些基准。当我遇到更多方法时,我将不断更新此答案,以便可以将其用作SO上其他参考。

#Utility function for plotting original, upsampled, and downsampled image

def plotit(img, up, down):
    fig, axes = plt.subplots(1,3, figsize=(10,15))
    axes[0].imshow(img)
    axes[1].imshow(up)
    axes[2].imshow(down)
    axes[0].title.set_text('Original')
    axes[1].title.set_text('Upsample')
    axes[2].title.set_text('Downsample')

IIUC,这有点像您的管道-

from scipy.ndimage import zoom
from skimage.data import camera

img = camera() #(512,512)
up = zoom(img,2) #upsample image

#some code
...

down = zoom(up,0.5) #downsample the upsampled image

plotit(img, up, down)

enter image description here


方法和基准 (in no specific order)

1。 Scipy zoom(order = 3)

使用给定顺序的样条插值缩放数组,在这种情况下,默认值为order = 3。

%%timeit
#from scipy.ndimage import zoom
up = zoom(img,2)
down = zoom(up,0.5)

#163 ms ± 12.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

2。 Scipy zoom(order = 0)

使用给定阶数的样条插值对数组进行缩放,在这种情况下,阶数= 0。

%%timeit
#from scipy.ndimage import zoom
up = zoom(img,2, order=0)
down = zoom(up,0.5, order=0)

#18.7 ms ± 950 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

3。 Skimage pyramid_gaussian

在高斯金字塔中,使用高斯平均(高斯模糊)对后续图像进行加权并进行缩放。对图像应用高斯模糊与将图像与高斯函数卷积相同。模糊程度取决于标准偏差大小(sigma)。

%%timeit
#from skimage.transform import import pyramid_gaussian
up = pyramid_gaussian(img,2)
down = pyramid_gaussian(up,0.5)

#471 ns ± 30.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

4。 Skimage pyramid_expandpyramid_reduce

图像金字塔是一种多尺度图像表示,其中图像要进行重复的平滑和二次采样。第一个函数先对图像进行平滑处理,然后再对图像进行升采样,而第二个函数执行相同的操作,但对图像进行降采样,默认情况下,这两个函数都使用样条线order = 1。

%%timeit
#from skimage.transform import import pyramid_expand, pyramid_reduce
up = pyramid_expand(img,2)
down = pyramid_reduce(up,2)

#120 ms ± 3.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

5。 Skimage rescale

按一定比例缩放图像。执行样条插值(默认情况下,order = 1)以放大或缩小N维图像。请注意,缩小图像尺寸时应启用抗锯齿功能,以免产生锯齿失真。

%%timeit
#from skimage.transform import import rescale
up = rescale(img,2)
down = rescale(up,0.5)

#83 ms ± 3.69 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

6。具有最近像素resize的PIL filter用于重采样

返回此图像的调整大小的副本。从输入图像中选择一个最近的像素。忽略所有其他输入像素。

%%timeit
#from PIL import Image
im = Image.fromarray(img)
up = im.resize((im.width*2, im.height*2),resample=Image.NEAREST)
down = up.resize((up.width//2, up.height//2),resample=Image.NEAREST)

#704 µs ± 29.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

7。 PIL resize和BILINEAR filter用于重采样

返回此图像的调整大小的副本。对于调整大小,在可能影响输出值的所有像素上使用线性插值计算输出像素值。对于其他转换,将在输入图像的2x2环境中使用线性插值。

%%timeit
#from PIL import Image
im = Image.fromarray(img)
up = im.resize((im.width*2, im.height*2),resample=Image.BILINEAR)
down = up.resize((up.width//2, up.height//2),resample=Image.BILINEAR)

#10.2 ms ± 877 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

8。 PIL resize和BICUBIC filter用于重采样

返回此图像的调整大小的副本。对于调整大小,对所有可能影响输出值的像素使用三次插值计算输出像素值。对于其他变换,使用输入图像中4x4环境上的三次插值。

%%timeit
#from PIL import Image
im = Image.fromarray(img)
up = im.resize((im.width*2, im.height*2),resample=Image.BICUBIC)
down = up.resize((up.width//2, up.height//2),resample=Image.BICUBIC)

#12.3 ms ± 326 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

9。与Lanczos resize进行PIL filter进行重采样

返回此图像的调整大小的副本。在所有可能影响输出值的像素上,使用高质量的Lanczos滤波器(截短的sinc)计算输出像素值。

%%timeit
#from PIL import Image
im = Image.fromarray(img)
up = im.resize((im.width*2, im.height*2),resample=Image.LANCZOS)
down = up.resize((up.width//2, up.height//2),resample=Image.LANCZOS)

#15.7 ms ± 184 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)