简体   繁体   English

没有VTK的python中的3D数据的插值/子采样

[英]Interpolation/subsampling of 3D data in python without VTK

What I want to do is rather simple but I havent found a straightforward approach thus far: 我想要做的是相当简单,但到目前为止我还没有找到一个简单的方法:

I have a 3D rectilinear grid with float values (therefore 3 coordinate axes -1D numpy arrays- for the centers of the grid cells and a 3D numpy array with the corresponding shape with a value for each cell center) and I want to interpolate (or you may call it subsample) this entire array to a subsampled array (eg size factor of 5) with linear interpolation. 我有一个带有浮点值的3D直线网格(因此3个坐标轴-1D numpy数组 - 用于网格单元的中心,3D numpy数组具有相应的形状,每个单元格中心都有一个值),我想插值(或您可以将其整个数组称为子样本数据(例如,尺寸因子为5),并使用线性插值。 All the approaches I've seen this far involve 2D and then 1D interpolation or VTK tricks which Id rather not use (portability). 我见过的所有方法都涉及2D,然后是1D插值或VTK技巧,而不是使用(可移植性)。

Could someone suggest an approach that would be the equivalent of taking 5x5x5 cells at the same time in the 3D array, averaging and returning an array 5times smaller in each direction? 有人会建议一种方法,相当于在3D阵列中同时取5x5x5单元,平均并返回每个方向5倍的阵列吗?

Thank you in advance for any suggestions 提前感谢您的任何建议

EDIT: Here's what the data looks like, 'd' is a 3D array representing a 3D grid of cells. 编辑:这是数据的样子,'d'是表示3D网格细胞的3D数组。 Each cell has a scalar float value (pressure in my case) and 'x','y' and 'z' are three 1D arrays containing the spatial coordinates of the cells of every cell (see the shapes and how the 'x' array looks like) 每个单元格都有一个标量浮点值(在我的情况下是压力),'x','y'和'z'是三个1D数组,包含每个单元格的单元格的空间坐标(参见形状以及'x'数组的方式)好像)

In [42]: x.shape
Out[42]: (181L,)

In [43]: y.shape
Out[43]: (181L,)

In [44]: z.shape
Out[44]: (421L,)

In [45]: d.shape
Out[45]: (181L, 181L, 421L)

In [46]: x
Out[46]: 
array([-0.410607  , -0.3927568 , -0.37780656, -0.36527296, -0.35475321,
       -0.34591168, -0.33846866, -0.33219107, -0.32688467, -0.3223876 ,
        ...
        0.34591168,  0.35475321,  0.36527296,  0.37780656,  0.3927568 ,
        0.410607  ])

What I want to do is create a 3D array with lets say a shape of 90x90x210 (roughly downsize by a factor of 2) by first subsampling the coordinates from the axes on arrays with the above dimensions and then 'interpolating' the 3D data to that array. 我想做的是创建一个3D数组,让我们说一个90x90x210的形状(大约缩小2倍),首先从具有上述尺寸的阵列上的轴上对坐标进行二次采样,然后将3D数据“插值”到那个阵列。 Im not sure whether 'interpolating' is the right term though. 我不确定'插值'是否是正确的术语。 Downsampling? 下采样? Averaging? 平均? Here's an 2D slice of the data: 这是数据的2D切片: 密度图

Here is an example of 3D interpolation on an irregular grid using scipy.interpolate.griddata . 以下是使用scipy.interpolate.griddata在不规则网格上进行3D插值的示例。

import numpy as np
import scipy.interpolate as interpolate
import matplotlib.pyplot as plt


def func(x, y, z):
    return x ** 2 + y ** 2 + z ** 2

# Nx, Ny, Nz = 181, 181, 421
Nx, Ny, Nz = 18, 18, 42

subsample = 2
Mx, My, Mz = Nx // subsample, Ny // subsample, Nz // subsample

# Define irregularly spaced arrays
x = np.random.random(Nx)
y = np.random.random(Ny)
z = np.random.random(Nz)

# Compute the matrix D of shape (Nx, Ny, Nz).
# D could be experimental data, but here I'll define it using func
# D[i,j,k] is associated with location (x[i], y[j], z[k])
X_irregular, Y_irregular, Z_irregular = (
    x[:, None, None], y[None, :, None], z[None, None, :])
D = func(X_irregular, Y_irregular, Z_irregular)

# Create a uniformly spaced grid
xi = np.linspace(x.min(), x.max(), Mx)
yi = np.linspace(y.min(), y.max(), My)
zi = np.linspace(y.min(), y.max(), Mz)
X_uniform, Y_uniform, Z_uniform = (
    xi[:, None, None], yi[None, :, None], zi[None, None, :])

# To use griddata, I need 1D-arrays for x, y, z of length 
# len(D.ravel()) = Nx*Ny*Nz.
# To do this, I broadcast up my *_irregular arrays to each be 
# of shape (Nx, Ny, Nz)
# and then use ravel() to make them 1D-arrays
X_irregular, Y_irregular, Z_irregular = np.broadcast_arrays(
    X_irregular, Y_irregular, Z_irregular)
D_interpolated = interpolate.griddata(
    (X_irregular.ravel(), Y_irregular.ravel(), Z_irregular.ravel()),
    D.ravel(),
    (X_uniform, Y_uniform, Z_uniform),
    method='linear')

print(D_interpolated.shape)
# (90, 90, 210)

# Make plots
fig, ax = plt.subplots(2)

# Choose a z value in the uniform z-grid
# Let's take the middle value
zindex = Mz // 2
z_crosssection = zi[zindex]

# Plot a cross-section of the raw irregularly spaced data
X_irr, Y_irr = np.meshgrid(sorted(x), sorted(y))
# find the value in the irregular z-grid closest to z_crosssection
z_near_cross = z[(np.abs(z - z_crosssection)).argmin()]
ax[0].contourf(X_irr, Y_irr, func(X_irr, Y_irr, z_near_cross))
ax[0].scatter(X_irr, Y_irr, c='white', s=20)   
ax[0].set_title('Cross-section of irregular data')
ax[0].set_xlim(x.min(), x.max())
ax[0].set_ylim(y.min(), y.max())

# Plot a cross-section of the Interpolated uniformly spaced data
X_unif, Y_unif = np.meshgrid(xi, yi)
ax[1].contourf(X_unif, Y_unif, D_interpolated[:, :, zindex])
ax[1].scatter(X_unif, Y_unif, c='white', s=20)
ax[1].set_title('Cross-section of downsampled and interpolated data')
ax[1].set_xlim(x.min(), x.max())
ax[1].set_ylim(y.min(), y.max())

plt.show()

在此输入图像描述

In short: doing interpolation in each dimension separately is the right way to go. 简而言之:分别在每个维度进行插值是正确的方法。


You can simply average every 5x5x5 cube and return the results. 您可以简单地平均每个5x5x5多维数据集并返回结果。 However, if your data is supposed to be continuous, you should understand that is not good subsampling practice, as it will likely induce aliasing. 但是,如果您的数据应该是连续的,您应该理解这不是一个好的子采样实践,因为它可能会导致混叠。 (Also, you can't reasonably call it "interpolation"!) (另外,你不能合理地称它为“插值”!)

Good resampling filters need to be wider than the resampling factor in order to avoid aliasing. 好的重采样滤波器需要比重采样因子更宽,以避免混叠。 Since you are downsampling, you should also realize that your resampling filter needs to be scaled according to the destination resolution, not the original resolution -- in order to interpolate properly, it will likely need to be 4 or 5 times as wide as your 5x5x5 cube. 由于您正在进行下采样,您还应该意识到您的重采样滤波器需要根据目标分辨率而不是原始分辨率进行缩放 - 为了正确插值,它可能需要是5x5x5的4或5倍宽立方体。 This is a lot of samples -- 20*20*20 is way more than 5*5*5 ... 这是很多样本 - 20*20*20超过5*5*5 ......

So, the reason why practical implementations of resampling typically filter each dimension separately is that it is more efficient. 因此,重新采样的实际实现通常分别过滤每个维度的原因是它更有效。 By taking 3 passes, you can evaluate your filter using far fewer multiply/accumulate operations per output sample. 通过3次传递,您可以使用每个输出样本少得多的乘法/累加运算来评估滤波器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM