Scipy интерполяция, как изменить размер/перемасштабировать матрицу 3x3 до 5x5?

EDIT: Пол решил это ниже. Спасибо!

Я пытаюсь переделать (масштабировать) матрицу 3x3 до 5x5, заполняя промежуточные точки интерполяцией .interp2d или интерполировать .RectBivariateSpline(или что-то работает).

Если есть простая, существующая функция для этого, я бы хотел ее использовать, но я еще не нашел ее. Например, функция, которая будет работать следующим образом:

# upscale 2x2 to 4x4
matrixSmall = ([[-1,8],[3,5]])
matrixBig = matrixSmall.resample(4,4,cubic)

Итак, если я начинаю с матрицы 3x3/array:

0,-2,0
-2,11,-2
0,-2,0

Я хочу вычислить новую матрицу 5x5 ( "I" означает интерполированное значение):

0, I[1,0], -2, I[3,0], 0
I[0,1], I[1,1], I[2,1], I[3,1], I[4,1]
-2, I[1,2], 11, I[3,2], -2
I[0,3], I[1,3], I[2,3], I[3,3], I[4,3]
0, I[1,4], -2, I[3,4], 0

Я искал и читал и пробовал различный тестовый код, но я не совсем понял правильный синтаксис для того, что я пытаюсь сделать. Я также не уверен, что мне нужно использовать meshgrid, mgrid или linspace в определенных строках.

EDIT: исправлено и работает Благодаря Paul

import numpy, scipy
from scipy import interpolate

kernelIn = numpy.array([[0,-2,0],
             [-2,11,-2],
             [0,-2,0]])

inKSize = len(kernelIn)
outKSize = 5

kernelOut = numpy.zeros((outKSize,outKSize),numpy.uint8)

x = numpy.array([0,1,2])
y = numpy.array([0,1,2])

z = kernelIn

xx = numpy.linspace(x.min(),x.max(),outKSize)
yy = numpy.linspace(y.min(),y.max(),outKSize)

newKernel = interpolate.RectBivariateSpline(x,y,z, kx=2,ky=2)

kernelOut = newKernel(xx,yy)

print kernelOut

Ответ 1

Только две небольшие проблемы:

1) Ваши xx, yy находятся за пределами x, y (вы можете экстраполировать, но я предполагаю, что вы не хотите.)

2) Ваш размер выборки слишком мал для kx и ky из 3 (по умолчанию). Опустите его на 2 и получите квадратичную форму вместо кубической.

import numpy, scipy
from scipy import interpolate

kernelIn = numpy.array([
    [0,-2,0],
    [-2,11,-2],
    [0,-2,0]])

inKSize = len(kernelIn)
outKSize = 5

kernelOut = numpy.zeros((outKSize),numpy.uint8)

x = numpy.array([0,1,2])
y = numpy.array([0,1,2])

z = kernelIn

xx = numpy.linspace(x.min(),x.max(),outKSize)
yy = numpy.linspace(y.min(),y.max(),outKSize)

newKernel = interpolate.RectBivariateSpline(x,y,z, kx=2,ky=2)

kernelOut = newKernel(xx,yy)

print kernelOut
##[[  0.      -1.5     -2.      -1.5      0.    ]
## [ -1.5      5.4375   7.75     5.4375  -1.5   ]
## [ -2.       7.75    11.       7.75    -2.    ]
## [ -1.5      5.4375   7.75     5.4375  -1.5   ]
## [  0.      -1.5     -2.      -1.5      0.    ]]

Ответ 2

Если вы используете scipy уже, я думаю, scipy.ndimage.interpolate.zoom может делать то, что вам нужно:

import numpy
import scipy.ndimage

a = numpy.array([[0.,-2.,0.], [-2.,11.,-2.], [0.,-2.,0.]])
out = numpy.round(scipy.ndimage.interpolation.zoom(input=a, zoom=(5./3), order = 2),1)

print out
#[[  0.   -1.   -2.   -1.    0. ]
# [ -1.    1.8   4.5   1.8  -1. ]
# [ -2.    4.5  11.    4.5  -2. ]
# [ -1.    1.8   4.5   1.8  -1. ]
# [  0.   -1.   -2.   -1.    0. ]]

Здесь коэффициент масштабирования 5./3, потому что мы переходим от массива 3x3 к массиву 5x5. Если вы читаете документы, в нем говорится, что вы также можете отдельно указать коэффициент масштабирования для двух осей, что означает, что вы также можете масштабировать неквадратные матрицы. По умолчанию он использует интернализацию сплайна третьего порядка, что я не уверен, что это лучше.

Я попробовал его на некоторых изображениях, и он работает красиво.