我有一个正方形的二维数组data
,我希望在一组给定的非整数坐标frame
处添加一个更大的二维数组coords
。我们的想法是data
将插入到frame
上,其中心位于新坐标处。
一些玩具数据:
# 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
这是个主意。我想补充一点:
到此:
得到这个:
如果坐标是整数(索引),我当然可以像这样添加它们:
frame[23:33,22:32] += data
但我希望能够指定非整数坐标,以便data
被重新调整并添加到frame
。
我研究过PIL.Image
方法,但我的用例仅用于2D数据,而不是图像。有没有办法只用scipy
来做到这一点?可以使用interp2d
或类似函数来完成吗?任何指导将不胜感激!
答案 0 :(得分:2)
scipy.ndimage.interpolation
和data
之间的网格间距重叠, frame
来自shift
的{{3}}函数就是您要找的内容。如果没有,请查看其他答案。 x
函数可以将浮点数作为输入,并进行样条插值。首先,我将数据放入一个与帧一样大的数组,然后移动它,然后添加它。确保反转坐标列表,因为numpy
是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()
数组中最右边的维度。 shift的一个很好的特性是它将那些超出界限的值设置为零。
public class CountActivity extends AppCompatActivity {
public int team_a_score;
public int team_a_foul;
public int team_a_corner;
public int team_b_score;
public int team_b_foul;
public int team_b_corner;
private Button goToDetailedStats;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_count);
goToDetailedStats = (Button) findViewById(R.id.go_to_stats);
goToDetailedStats.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
openDetailedScore();
}
});
}
private void openDetailedScore() {
Intent intent = new Intent(this,DeatiledScoreActivity.class);
intent.putExtra("",team_a_score);
intent.putExtra("",team_a_foul);
intent.putExtra("",team_a_corner);
startActivity(intent);
}
public void resetScore(View view) {
team_a_score = 0;
display_a_score(team_a_score);
team_b_score = 0;
display_b_score(team_b_score);
}
private void display_a_score (int a_score){
TextView team_a_score_tv = (TextView) findViewById(R.id.team_a_score_tv);
team_a_score_tv.setText(String.valueOf(a_score));
}
private void display_b_score (int b_score){
TextView team_b_score_tv = (TextView) findViewById(R.id.team_b_score_tv);
team_b_score_tv.setText(String.valueOf(b_score));
}
public void increment_a_score(View view) {
team_a_score = team_a_score+1;
display_a_score(team_a_score);
}
public void increment_a_foul(View view) {
team_a_foul = team_a_foul+1;
}
public void increment_a_corner(View view) {
team_a_corner = team_a_corner+1;
}
public void increment_b_score(View view) {
team_b_score = team_b_score+1;
display_b_score(team_b_score);
}
public void increment_b_foul(View view) {
team_b_foul = team_b_foul+1;
}
public void increment_b_corner(View view) {
team_b_corner = team_b_corner+1;
}
}
该脚本为您提供了下图,其中所需的坐标用白色虚线表示。
答案 1 :(得分:1)
一种可能的解决方案是使用scipy.interpolate.RectBivariateSpline
。在下面的代码中,x_0
和y_0
是数据中要素的坐标(即,示例中高斯中心的位置),需要映射到{给出的坐标{1}}。这种方法有几个优点:
如果你需要"放置"将相同的对象放入输出coords
中的多个位置,样条只需要计算一次(但多次计算)。
如果您确实需要计算模型在像素上的积分通量,则可以使用frame
的{{3}}。
使用样条插值重新取样:
scipy.interpolate.RectBivariateSpline
现在绘制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
并重新采样frame
:
data
如果您还想允许进行比例更改,请使用以下代码替换上面计算plt.figure(figsize=(14, 14));
plt.imshow(frame+resampled_data, cmap=plt.cm.jet,
origin='upper', interpolation='none', aspect='equal')
plt.show()
和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
中像素的坐标是&#34;间隔&#34;乘以0.222(2)个距离单位。因此,实际上,对于您的特定示例(无论是偶然的还是有意的),您的缩放因子为0.222(2)。在这种情况下,您的data
图像将缩小到输出帧中的近2个像素。
data
回答的比较在下图中,我比较了我的方法(左),@Chiel
的方法(中心)和差异(右图)的结果:
从根本上说,这两种方法非常相似,甚至可能使用相同的算法(我没有查看@Chiel
的代码,但基于描述 - 它也使用样条线)。从比较图像可以看出,最大的差异在于边缘,而且由于我不知道原因,shift
似乎过早地截断了移位的图像。
我认为最大的区别在于我的方法允许像素比例变化,并且它还允许重复使用相同的内插器将原始图像放置在输出帧中的不同位置。 shift
的方法稍微简单但是(我不喜欢它的是)它需要创建一个更大的数组(@Chiel
),原始图像放在角落里
答案 2 :(得分:0)
虽然其他答案已经详细说明,但这是我的懒惰解决方案:
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
这就是你喜欢它的方式。正如您所提到的,两者的坐标是相同的,因此data
的原点介于索引之间。现在只需简单地将它移动到你希望它离开第二行的网格点(余数为1)并且你很好(你可能需要翻转标志,但我认为这是正确的)。