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. Если вы читаете документы, в нем говорится, что вы также можете отдельно указать коэффициент масштабирования для двух осей, что означает, что вы также можете масштабировать неквадратные матрицы. По умолчанию он использует интернализацию сплайна третьего порядка, что я не уверен, что это лучше.
Я попробовал его на некоторых изображениях, и он работает красиво.