scipy.ndimage.interpolation.zoom使用类似最近邻居的算法进行缩减

Max*_*aev 6 python image-processing scipy

在测试scipy的缩放功能时,我发现scailng-down数组的结果与最近邻算法类似,而不是平均.这极大地增加了噪声,并且对于许多应用而言通常是次优的.

是否存在不使用类似最近邻算法的替代方案,并在缩小尺寸时正确平均数组?虽然粗粒度适用于整数缩放因子,但我也需要非整数缩放因子.

测试用例:创建一个随机的100*M x 100*M阵列,对于M = 2..20将阵列缩小M系数的三种方式:

1)通过在MxM块中取平均值2)通过使用scipy的缩放比例因子1/M 3)获取a中的第一个点

得到的数组具有相同的平均值,相同的形状,但scipy的数组具有与最近邻居一样高的方差.为scipy.zoom采取不同的顺序并没有真正帮助.

import scipy.ndimage.interpolation
import numpy as np
import matplotlib.pyplot as plt

mean1, mean2, var1, var2, var3  = [],[],[],[],[]
values = range(1,20)  # down-scaling factors

for M in values:
    N = 100  # size of an array 
    a = np.random.random((N*M,N*M))  # large array    

    b = np.reshape(a, (N, M, N, M))  
    b = np.mean(np.mean(b, axis=3), axis=1)
    assert b.shape == (N,N)  #coarsegrained array

    c = scipy.ndimage.interpolation.zoom(a, 1./M, order=3, prefilter = True) 
    assert c.shape == b.shape

    d = a[::M, ::M]  # picking one random point within MxM block
    assert b.shape == d.shape

    mean1.append(b.mean())
    mean2.append(c.mean())
    var1.append(b.var())
    var2.append(c.var())
    var3.append(d.var())

plt.plot(values, mean1, label = "Mean coarsegraining")
plt.plot(values, mean2, label = "mean scipy.zoom")
plt.plot(values, var1, label = "Variance coarsegraining")
plt.plot(values, var2, label = "Variance zoom")
plt.plot(values, var3, label = "Variance Neareset neighbor")
plt.xscale("log")
plt.yscale("log")
plt.legend(loc=0)
plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

编辑:scipy.ndimage.zoom在真实的嘈杂图像上的表现也很差

在此输入图像描述

原始图片在http://wiz.mit.edu/lena_noisy.png

产生它的代码:

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from scipy.ndimage.interpolation import zoom

im = Image.open("/home/magus/Downloads/lena_noisy.png")
im = np.array(im)

plt.subplot(131)
plt.title("Original")
plt.imshow(im, cmap="Greys_r")

plt.subplot(132)
im2 = zoom(im, 1 / 8.)
plt.title("Scipy zoom 8x")
plt.imshow(im2, cmap="Greys_r", interpolation="none")

im.shape = (64, 8, 64, 8)
im3 = np.mean(im, axis=3)
im3 = np.mean(im3, axis=1)

plt.subplot(133)
plt.imshow(im3, cmap="Greys_r", interpolation="none")
plt.title("averaging over 8x8 blocks")

plt.show()
Run Code Online (Sandbox Code Playgroud)

And*_*sky 1

FWIW我发现 order=1 至少比默认值或 order=3 更好地保留了平均值(确实如预期)