[英]Regrid 2D data onto larger 2D grid at given coordinates in Python
I have a square 2D array data
that I would like to add to a larger 2D array frame
at some given set of non-integer coordinates coords
. 我有一个方形2D数组
data
,我想在给定的一组非整数坐标coords
处将其添加到更大的2D数组frame
中。 The idea is that data
will be interpolated onto frame
with it's center at the new coordinates. 这个想法是将
data
以新坐标的中心插入到frame
。
Some toy data: 一些玩具数据:
# A gaussian to add to the frame
x, y = np.meshgrid(np.linspace(-1,1,10), np.linspace(-1,1,10))
data = 50*np.exp(-np.sqrt(x**2+y**2)**2)
# The frame to add the gaussian to
frame = np.random.normal(size=(100,50))
# The desired (x,y) location of the gaussian center on the new frame
coords = 23.4, 22.6
Here's the idea. 这是主意。 I want to add this:
我要添加:
to this: 对此:
to get this: 得到这个:
If the coordinates were integers (indexes), of course I could simply add them like this: 如果坐标是整数(索引),那么我当然可以像这样简单地添加它们:
frame[23:33,22:32] += data
But I want to be able to specify non-integer coordinates so that data
is regridded and added to frame
. 但我希望能够指定非整数坐标,以便将
data
重新注册并添加到frame
。
I've looked into PIL.Image
methods but my use case is just for 2D data, not images. 我已经研究了
PIL.Image
方法,但是我的用例仅用于2D数据,而不是图像。 Is there a way to do this with just scipy
? 有没有办法做到这
scipy
? Can this be done with interp2d
or a similar function? 可以使用
interp2d
或类似的功能吗? Any guidance would be greatly appreciated! 任何指导将不胜感激!
Scipy's shift
function from scipy.ndimage.interpolation
is what you are looking for, as long as the grid spacings between data
and frame
overlap. 您正在寻找
scipy.ndimage.interpolation
Scipy shift
功能,只要data
和frame
之间的网格间距重叠即可。 If not, look to the other answer. 如果不是,请寻找其他答案。 The
shift
function can take floating point numbers as input and will do a spline interpolation. shift
功能可以将浮点数作为输入,并进行样条插值。 First, I put the data into an array as large as frame, then shift it, and then add it. 首先,我将数据放入与框架一样大的数组中,然后将其移位,然后添加。 Make sure to reverse the coordinate list, as
x
is the rightmost dimension in numpy
arrays. 确保反转坐标列表,因为
x
是numpy
数组中最右边的维。 One of the nice features of shift is that it sets to zero those values that go out of bounds. shift的一个不错的功能之一就是将超出范围的值设置为零。
import numpy as np
import matplotlib.pyplot as plt
from scipy.ndimage.interpolation import shift
# A gaussian to add to the frame.
x, y = np.meshgrid(np.linspace(-1,1,10), np.linspace(-1,1,10))
data = 50*np.exp(-np.sqrt(x**2+y**2)**2)
# The frame to add the gaussian to
frame = np.random.normal(size=(100,50))
x_frame = np.arange(50)
y_frame = np.arange(100)
# The desired (x,y) location of the gaussian center on the new frame.
coords = np.array([23.4, 22.6])
# First, create a frame as large as the frame.
data_large = np.zeros(frame.shape)
data_large[:data.shape[0], :data.shape[1]] = data[:,:]
# Subtract half the distance as the bottom left is at 0,0 instead of the center.
# The shift of 4.5 is because data is 10 points wide.
# Reverse the coords array as x is the last coordinate.
coords_shift = -4.5
data_large = shift(data_large, coords[::-1] + coords_shift)
frame += data_large
# Plot the result and add lines to indicate to coordinates
plt.figure()
plt.pcolormesh(x_frame, y_frame, frame, cmap=plt.cm.jet)
plt.axhline(coords[1], color='w')
plt.axvline(coords[0], color='w')
plt.colorbar()
plt.gca().invert_yaxis()
plt.show()
The script gives you the following figure, which has the desired coordinates indicated with white dotted lines. 该脚本为您提供下图,该图具有用白色虚线表示的所需坐标。
One possible solution is to use scipy.interpolate.RectBivariateSpline
. 一种可能的解决方案是使用
scipy.interpolate.RectBivariateSpline
。 In the code below, x_0
and y_0
are the coordinates of a feature from data (ie, the position of the center of the Gaussian in your example) that need to be mapped to the coordinates given by coords
. 在下面的代码中,
x_0
和y_0
是数据中要素的坐标(例如,您的示例中高斯中心的位置),需要将其映射到coords
给出的coords
。 There are a couple of advantages to this approach: 这种方法有两个优点:
If you need to "place" the same object into multiple locations in the output frame
, the spline needs to be computed only once (but evaluated multiple times). 如果需要将同一对象“放置”到输出
frame
中的多个位置,则样条线只需要计算一次(但是需要多次评估)。
In case you actually need to compute integrated flux of the model over a pixel, you can use the integral
method of scipy.interpolate.RectBivariateSpline
. 如果您实际上需要计算模型在一个像素上的积分通量,则可以使用
scipy.interpolate.RectBivariateSpline
的integral
方法 。
Resample using spline interpolation: 使用样条插值重新采样:
from scipy.interpolate import RectBivariateSpline
x = np.arange(data.shape[1], dtype=np.float)
y = np.arange(data.shape[0], dtype=np.float)
kx = 3; ky = 3; # spline degree
spline = RectBivariateSpline(
x, y, data.T, kx=kx, ky=ky, s=0
)
# Define coordinates of a feature in the data array.
# This can be the center of the Gaussian:
x_0 = (data.shape[1] - 1.0) / 2.0
y_0 = (data.shape[0] - 1.0) / 2.0
# create output grid, shifted as necessary:
yg, xg = np.indices(frame.shape, dtype=np.float64)
xg += x_0 - coords[0] # see below how to account for pixel scale change
yg += y_0 - coords[1] # see below how to account for pixel scale change
# resample and fill extrapolated points with 0:
resampled_data = spline.ev(xg, yg)
extrapol = (((xg < -0.5) | (xg >= data.shape[1] - 0.5)) |
((yg < -0.5) | (yg >= data.shape[0] - 0.5)))
resampled_data[extrapol] = 0
Now plot the frame
and resampled data
: 现在绘制
frame
并重新采样data
:
plt.figure(figsize=(14, 14));
plt.imshow(frame+resampled_data, cmap=plt.cm.jet,
origin='upper', interpolation='none', aspect='equal')
plt.show()
If you also want to allow for scale changes, then replace code for computing xg
and yg
above with: 如果您还希望允许比例更改,则将上面用于计算
xg
和yg
代码替换为:
coords = 20, 80 # change coords to easily identifiable (in plot) values
zoom_x = 2 # example scale change along X axis
zoom_y = 3 # example scale change along Y axis
yg, xg = np.indices(frame.shape, dtype=np.float64)
xg = (xg - coords[0]) / zoom_x + x_0
yg = (yg - coords[1]) / zoom_y + y_0
Most likely this is what you actually want based on your example. 根据示例,这很可能是您真正想要的。 Specifically, the coordinates of pixels in
data
are "spaced" by 0.222(2) distance units. 具体而言,
data
中像素的坐标以0.222(2)个距离单位“间隔开”。 Therefore it actually seems that for your particular example (whether accidental or intentional), you have a zoom factor of 0.222(2). 因此,实际上,对于您的特定示例(无论是偶然的还是有意的),您的缩放系数为0.222(2)。 In that case your
data
image would shrink to almost 2 pixels in the output frame. 在这种情况下,您的
data
图像在输出帧中将缩小到几乎2个像素。
@Chiel
answer @Chiel
答案的比较 In the image below, I compare the results from my method (left), @Chiel
's method (center) and difference (right panel): 在下图中,我比较了我的方法(左),
@Chiel
的方法(中)和差异(右图)的结果:
Fundamentally, the two methods are quite similar and possibly even use the same algorithm (I did not look at the code for shift
but based on the description - it also uses splines). 从根本上讲,这两种方法非常相似,甚至可能使用相同的算法(我没有查看
shift
代码,而是基于描述-它也使用样条线)。 From comparison image it is visible that the biggest differences are at the edges and, for unknown to me reasons, shift
seems to truncate the shifted image slightly too soon. 从比较图像中可以看出,最大的差异在边缘,并且由于我所不知道的原因,
shift
似乎太快地截断了移位的图像。
I think the biggest difference is that my method allows for pixel scale changes and it also allows re-use of the same interpolator to place the original image at different locations in the output frame. 我认为最大的不同是,我的方法可以改变像素比例,并且还可以重复使用相同的插值器将原始图像放置在输出帧的不同位置。
@Chiel
's method is somewhat simpler but (what I did not like about it is that) it requires creation of a larger array ( data_large
) into which the original image is placed in the corner. @Chiel
的方法稍微简单一些,但是(我不喜欢的是)它需要创建一个更大的数组( data_large
),将原始图像放置在其中。
While the other answers have gone into detail, but here's my lazy solution: 虽然其他答案已经详细介绍了,但这是我的懒惰解决方案:
xc,yc = 23.4, 22.6
x, y = np.meshgrid(np.linspace(-1,1,10)-xc%1, np.linspace(-1,1,10)-yc%1)
data = 50*np.exp(-np.sqrt(x**2+y**2)**2)
frame = np.random.normal(size=(100,50))
frame[23:33,22:32] += data
And it's the way you liked it. 这就是您喜欢它的方式。 As you mentioned, the coordinates of both are the same, so the origin of
data
is somewhere between the indices. 正如您提到的,两者的坐标是相同的,因此
data
的原点在索引之间。 Now just simply shift it by the amount you want it to be off a grid point (remainder to one) in the second line and you're good to go (you might need to flip the sign, but I think this is correct). 现在只需简单地将其偏移第二行中您希望其偏离网格点的数量(保留为一个),就可以了(您可能需要翻转符号,但我认为这是正确的)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.