在Python中的给定坐标处将2D数据重新划分到更大的2D网格上

时间:2018-06-15 18:58:11

标签: python numpy scipy python-imaging-library

我有一个正方形的二维数组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

这是个主意。我想补充一点:

gaussian

到此:

enter image description here

得到这个:

enter image description here

如果坐标是整数(索引),我当然可以像这样添加它们:

frame[23:33,22:32] += data

但我希望能够指定非整数坐标,以便data被重新调整并添加到frame

我研究过PIL.Image方法,但我的用例仅用于2D数据,而不是图像。有没有办法只用scipy来做到这一点?可以使用interp2d或类似函数来完成吗?任何指导将不胜感激!

3 个答案:

答案 0 :(得分:2)

只要scipy.ndimage.interpolationdata之间的网格间距重叠,

frame来自shift的{​​{3}}函数就是您要找的内容。如果没有,请查看其他答案。 x函数可以将浮点数作为输入,并进行样条插值。首先,我将数据放入一个与帧一样大的数组,然后移动它,然后添加它。确保反转坐标列表,因为numpyimport 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;
}
} 

该脚本为您提供了下图,其中所需的坐标用白色虚线表示。

shift

答案 1 :(得分:1)

一种可能的解决方案是使用scipy.interpolate.RectBivariateSpline。在下面的代码中,x_0y_0是数据中要素的坐标(即,示例中高斯中心的位置),需要映射到{给出的坐标{1}}。这种方法有几个优点:

  1. 如果你需要"放置"将相同的对象放入输出coords中的多个位置,样条只需要计算一次(但多次计算)。

  2. 如果您确实需要计算模型在像素上的积分通量,则可以使用frame的{​​{3}}。

  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

    integral method

    如果您还想允许进行比例更改,请使用以下代码替换上面计算plt.figure(figsize=(14, 14)); plt.imshow(frame+resampled_data, cmap=plt.cm.jet, origin='upper', interpolation='none', aspect='equal') plt.show() xg的代码:

    yg

    enter image description here

    根据您的示例,这很可能是您真正想要的。具体来说,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的方法(中心)和差异(右图)的结果:

    enter image description here

    从根本上说,这两种方法非常相似,甚至可能使用相同的算法(我没有查看@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)并且你很好(你可能需要翻转标志,但我认为这是正确的)。