how to interpolate a numpy array with linear interpolation - python

I have a numpy array which has the following shape: (1, 128, 160, 1).
Now, I have an image which has the shape: (200, 200).
So, I do the following:
orig = np.random.rand(1, 128, 160, 1)
orig = np.squeeze(orig)
Now, what I want to do is take my original array and interpolate it to be of the same size as the input image i.e. (200, 200) using linear interpolation. I think I have to specify the grid on which the numpy array should be evaluated but I am unable to figure out how to do it.

You can do it with scipy.interpolate.interp2d like this:
from scipy import interpolate
# Make a fake image - you can use yours.
image = np.ones((200,200))
# Make your orig array (skipping the extra dimensions).
orig = np.random.rand(128, 160)
# Make its coordinates; x is horizontal.
x = np.linspace(0, image.shape[1], orig.shape[1])
y = np.linspace(0, image.shape[0], orig.shape[0])
# Make the interpolator function.
f = interpolate.interp2d(x, y, orig, kind='linear')
# Construct the new coordinate arrays.
x_new = np.arange(0, image.shape[1])
y_new = np.arange(0, image.shape[0])
# Do the interpolation.
new_orig = f(x_new, y_new)
Note the -1 adjustment to the coordinate range when forming x and y. This ensures that the image coordinates go from 0 to 199 inclusive.

Related

Order of dimensions for a multivariate (4d) normal distribution using scipy / python?

I would like to evaluate a 4d Gaussian / normal distribution on a 4d grid. Let's call the variables (x1,y1,x2,y2). Then if I have means = (x1=1,y1=0,x2=2,y2=0), I expect that when I do a 2d contour plot in the x1, x2 direction, at y1=y2=0, to see a Gaussian centered in (x1=1, x2=2). However, I see the mean/center at (x1=2,x2=0) instead.
What am I missing here? Is it how I define the grid to begin with?
For a 2d normal distribution it works as expected.
import numpy as np
from matplotlib import pyplot as plt
from scipy.stats import multivariate_normal
xy_min = -5
xy_max = 5
npoints = 50
x = np.linspace(xy_min, xy_max, npoints)
dim = 4
xx1,yy1,xx2,yy2 = np.meshgrid(x, x,x,x)
points = np.concatenate([xx1[:, :,:, :,None], yy1[:, :, :,:,None],xx2[:, :, :,:,None],yy2[:, :, :,:,None]], axis=-1)
cov = np.diag(np.ones(4))
mean=np.array([1,0,2,0])
rv = multivariate_normal.pdf(points , mean=mean, cov=cov)
plt.figure()
plt.contourf(x, x, rv[:,0,:,0])
I tried to manually reshape the evaluation points first, but it gives the same results. So I think I am missing something conceptually here?
points_resh = np.reshape(points,[npoints**4,dim],order='C')
rv_resh = multivariate_normal.pdf(points_resh , mean=mean, cov=cov)
rv2 = np.reshape(rv_resh,[npoints,npoints,npoints,npoints],order='C')
plt.figure()
plt.contourf(x, x, rv2[:,0,:,0])
** EDIT: SOLVED **
using ij indexing for meshgrid everything works as expected. Only need to keep in mind that the matrix needs to be transposed for contour plotting. See example below:
#%% Instead use ij indexing
x = np.linspace(-5, 5, 50)
y = np.linspace(-3, 3, 30)
z= np.linspace(-2, 2, 20)
w= np.linspace(-1, 1, 10)
x4d,y4d,z4d,w4d= np.meshgrid(x, y,z,w,indexing='ij')
points4d= np.concatenate([x4d[:, :,:,:,None], y4d[:, :,:,:,None], z4d[:, :,:,:,None],w4d[:, :,:,:,None]], axis=-1)
rv4d = multivariate_normal.pdf(points4d , mean=[1,0.0,2,0.0], cov=[0.1,0.1,0.1,0.1])
fig,ax=plt.subplots()
ax.contourf(x,z,rv4d[:,0,:,0].T)
ax.set(xlabel='x',ylabel='y')
print(x_mean)
using ij indexing for meshgrid everything works as expected. Only need to keep in mind that the matrix needs to be transposed for contour plotting. See example below:
#%% Instead use ij indexing
x = np.linspace(-5, 5, 50)
y = np.linspace(-3, 3, 30)
z= np.linspace(-2, 2, 20)
w= np.linspace(-1, 1, 10)
x4d,y4d,z4d,w4d= np.meshgrid(x, y,z,w,indexing='ij')
points4d= np.concatenate([x4d[:, :,:,:,None], y4d[:, :,:,:,None], z4d[:, :,:,:,None],w4d[:, :,:,:,None]], axis=-1)
rv4d = multivariate_normal.pdf(points4d , mean=[1,0.0,2,0.0], cov=[0.1,0.1,0.1,0.1])
fig,ax=plt.subplots()
ax.contourf(x,z,rv4d[:,0,:,0].T)
ax.set(xlabel='x',ylabel='y')
print(x_mean)

Reshape multi-temporal, mutlispectral 3D numpy arrays

I'm working with multi-temporal, multispectral satellite imagery. The data are stored as geotiffs in the shape ((n_bands x n_timesteps), height, width). I need to reshape the array for ML model training where each pixel in the image is a "sample". The training array would therefore be shape (n_samples x n_timesteps x n_bands).
Assume the following array and associated variables. Also assume the number of bands in the dataset is 12 and the number if time steps is 4. Therefore, the first dimension of the array is 12*4 = 48.
x = np.random.rand(48, 512, 512)
width = x.shape[1]
height = x.shape[2]
n_samples = width * height
n_bands = 12
n_timesteps = x.shape[0] / n_bands
What is the best way to reshape the array x to x_reshape such that x_reshape.shape returns:
(n_samples, n_timesteps, n_bands)
Making sure to preserve the correct ordering of the data such that a slice of x_reshape[0] is a single "sample" of the dataset of shape (n_timesteps x n_features)?
You can use numpy.reshape() and after that numpy.moveaxis() to achieve what you want:
import numpy as np
x = np.random.rand(48, 512, 512)
width = x.shape[1]
height = x.shape[2]
n_samples = width * height
n_bands = 12
n_timesteps = int(x.shape[0] / n_bands)
x = np.reshape(x, (n_timesteps,n_bands,n_samples))
x = np.moveaxis(x, -1, 0)

NumPy array of indexing arrays

I have a NumPy array with shape (300, 500). Consider this as an image with size (300, 500) and there are 100 objects on it that I want to fill each of them with a different value.
image = np.zeros((300, 500))
I have bounding-box coordinates (x_min, x_max, y_min, y_max) for each of these objects. Then I create indexing arrays using these bounding-box coordinates.
array_of_x_indexing_arrays = []
array_of_y_indexing_arrays = []
for obj in objects:
x_indices, y_indices = np.mgrid[obj.x_min: obj.x_max + 1, obj.y_min: obj.y_max + 1]
x_indices, y_indices = x_indices.ravel(), y_indices.ravel()
array_of_x_indexing_arrays.append(x_indices)
array_of_y_indexing_arrays.append(y_indices)
Then, I want to assign a different value to image for each of these objects. I stored them the values for each object in an array with shape (100,)
data = np.array((100,))
# Assume that I filled data such as
# data[0] = 10
# data[1] = 2
# ...
# data[99] = 3
Then what I want to do is following
for i in range(len(objects)):
image[array_of_y_indexing_arrays[i], array_of_x_indexing_arrays[i]] = data[i]
But I want to do this in NumPy way, I have tried the following but does not work
image[array_of_y_indexing_arrays, array_of_x_indexing_arrays] = data

How to efficiently draw a plot of a torch.nn model?

I'm exploring neural networks, and I want to model some pictures with neural network. Picture is a function that maps pixel coordinates to color, so I make my network also with 2 input variables (x, y) and 1 (shade) to 3 (R, G, B) output coordinates. For example, like this:
import torch.nn as nn
net = nn.Sequential(
nn.Linear(2, 2),
nn.Sigmoid(),
nn.Linear(2, 1),
)
Now, I plot it like this:
import matplotlib.pyplot as plt
import numpy as np
def draw_image1(f):
image = []
y = 1
delta = 0.005
while y > 0:
x = 0
row = []
while x < 1:
row.append(f(x, y))
x += delta
image.append(row)
y -= delta
plt.imshow(image, extent=[0, 1, 0, 1], cmap='winter')
plt.draw()
draw_image1(lambda x, y: net(torch.Tensor([x, y])).item())
But it looks ugly and is slow because it uses Python lists instead of numpy arrays or tensors.
I have another version of code that draws images from functions, which looks better and is 100x faster:
def draw_image2(f):
x = np.linspace(0, 1, num = 200)
y = np.linspace(0, 1, num = 200)
X, Y = np.meshgrid(x, y)
image = f(X, Y)
plt.imshow(image, extent=[0, 1, 0, 1], cmap='winter')
plt.draw()
It works for functions that use numpy operations (like lambda x: x + y), but when I plug in my net in the same way as for previous function (draw_image2(lambda x, y: net(torch.Tensor([x, y])).item())), I get RuntimeError: mat1 and mat2 shapes cannot be multiplied (400x200 and 2x2), which I understand as my neural net complaining that it wants to be fed data in smaller pieces.
Is there any proper way to plot pytorch neural network output?
To feed a whole batch into nn.Linear(i, o), the input typically has the shape (b, i) where b is the size of the batch. If we take a look at the documentation you can actually use additional "batch"-dimensions in between. Actually since pytorch was primarily made for deep learning that is based on stochastic gradietn descent, pretty much all modules of pytorch require you to have at least one batch dimension.
So you could easily modify your second plotting function to something like:
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
net = nn.Sequential(
nn.Linear(2, 2),
nn.Sigmoid(),
nn.Linear(2, 1),
)
def draw_image2(f):
device = torch.device('cpu') # or use your gpu alternatively
with torch.no_grad(): # disable building evaluation graph if you don't need it
x = torch.linspace(0, 1, 200)
y = torch.linspace(0, 1, 200)
X, Y = torch.meshgrid(x, y)
# the data dimension should be the last (2), as per documentation
inp = torch.stack([X, Y], dim=2).to(device) # shape = (200, 200, 2)
image = f(inp) # shape = (200, 200, 1)
image = image[..., 0].detach().cpu() # shape (200, 200)
plt.imshow(image, extent=[0, 1, 0, 1], cmap='winter')
plt.show()
return image
draw_image2(net)
Note that the with torch.no_grad() is not necessary for it to work, but it will save you some time. Depending on your network architecture it might also be worth to set your network to eval mode (net.eval()) first. Finally the .to(device)/.cpu() is also not necessary if you're not using your GPU.

How can I interpolate data in python?

I have a 4D dataset (time, z, y, x) and I would like to interpolate the data to get a higher resolution, this is a simple example code:
import numpy as np
from scipy.interpolate import griddata
x_0 = 10
cut_index = 10
res = 200j
x_index = x_0
y_index = np.linspace(0, 100, 50).astype(int)
z_index = np.linspace(0, 50, 25).astype(int)
#Time, zyx-coordinate
u = np.random.randn(20, 110, 110, 110)
z_index, y_index = np.meshgrid(z_index, y_index)
data = u[cut_index, z_index, y_index, x_index]
res = 200j
y_f = np.mgrid[0:100:res]
z_f = np.mgrid[0:50:res]
z_f, y_f = np.meshgrid(z_f, y_f)
data = griddata((z_index, y_index), data, (z_f, y_f))
I am getting the ValueError: invalid shape for input data points error. What kind of input is expected by the griddata function?
Your data parameter has to be a 1D array. Try flattening the arrays:
data = griddata((z_index.flatten(), y_index.flatten()), data.flatten(), (z_f, y_f))

Categories