簡體   English   中英

沒有VTK的python中的3D數據的插值/子采樣

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

我想要做的是相當簡單,但到目前為止我還沒有找到一個簡單的方法:

我有一個帶有浮點值的3D直線網格(因此3個坐標軸-1D numpy數組 - 用於網格單元的中心,3D numpy數組具有相應的形狀,每個單元格中心都有一個值),我想插值(或您可以將其整個數組稱為子樣本數據(例如,尺寸因子為5),並使用線性插值。 我見過的所有方法都涉及2D,然后是1D插值或VTK技巧,而不是使用(可移植性)。

有人會建議一種方法,相當於在3D陣列中同時取5x5x5單元,平均並返回每個方向5倍的陣列嗎?

提前感謝您的任何建議

編輯:這是數據的樣子,'d'是表示3D網格細胞的3D數組。 每個單元格都有一個標量浮點值(在我的情況下是壓力),'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  ])

我想做的是創建一個3D數組,讓我們說一個90x90x210的形狀(大約縮小2倍),首先從具有上述尺寸的陣列上的軸上對坐標進行二次采樣,然后將3D數據“插值”到那個陣列。 我不確定'插值'是否是正確的術語。 下采樣? 平均? 這是數據的2D切片: 密度圖

以下是使用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()

在此輸入圖像描述

簡而言之:分別在每個維度進行插值是正確的方法。


您可以簡單地平均每個5x5x5多維數據集並返回結果。 但是,如果您的數據應該是連續的,您應該理解這不是一個好的子采樣實踐,因為它可能會導致混疊。 (另外,你不能合理地稱它為“插值”!)

好的重采樣濾波器需要比重采樣因子更寬,以避免混疊。 由於您正在進行下采樣,您還應該意識到您的重采樣濾波器需要根據目標分辨率而不是原始分辨率進行縮放 - 為了正確插值,它可能需要是5x5x5的4或5倍寬立方體。 這是很多樣本 - 20*20*20超過5*5*5 ......

因此,重新采樣的實際實現通常分別過濾每個維度的原因是它更有效。 通過3次傳遞,您可以使用每個輸出樣本少得多的乘法/累加運算來評估濾波器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM