Skip to content

MATLAB - 三维数组插值

三维 (3D) 插值是在给定一组排列在网格上的已知数据点的情况下,估算 3D 空间中任意点的值的过程。这项技术在许多科学和工程领域中都至关重要,例如医学成像(例如,对 MRI 扫描进行升采样)、计算流体力学 (CFD) 和地球物理数据分析。它允许您创建更平滑的可视化效果、提高数据分辨率或查询未明确测量的位置的值。

MATLAB 用于此任务的主要工具是 interp3 函数。

Vq = interp3(X, Y, Z, V, Xq, Yq, Zq)
Vq = interp3(V, Xq, Yq, Zq)
Vq = interp3(V, k)
Vq = interp3(___, method)
Vq = interp3(___, method, extrapolation_val)
  • Vq = interp3(X,Y,Z,V,Xq,Yq,Zq):这是最明确的形式。它对 3D 数组 V(在网格坐标 X,Y,Z 定义)中的数据进行插值,以在新的查询坐标 Xq,Yq,Zq 处找到值 Vq。
  • Vq = interp3(V,Xq,Yq,Zq):一种更简单的形式,它假定一个默认采样网格(1:size(V,2)、1:size(V,1)、1:size(V,3))。
  • Vq = interp3(V,k):将网格细化 2^k 倍。例如,k=1 会在所有三个维度中,在每个现有采样点之间插入一个新的点。
  • ... , method):指定插值算法。常见的选择包括:
    • 'linear'(默认):快速且相当准确。一个很好的首选。
    • 'nearest':最快,但会产生块状、不连续的输出。
    • 'cubic':分段三次插值。产生比线性插值更平滑的结果,但计算量更大。
    • 'spline':样条插值。通常产生最平滑的结果,但计算量也最大。
    • 'makima':一种改进的 Akima 三次插值,可避免有时在 'cubic' 中出现的超调。

让我们通过实际示例探索 interp3。请注意,我们将以文本形式描述图表,因为不使用图像。

在这里,我们创建一个粗糙的 3D 数据集,并使用 interp3 生成一个更精细、更平滑的版本。

% 1. 定义粗糙网格和采样数据
[X, Y, Z] = meshgrid(1:5, 1:5, 1:5);
V = Z.^2 .* sqrt(X.^2 + Y.^2);
% 2. 定义更精细的查询网格
[Xq, Yq, Zq] = meshgrid(1:0.25:5, 1:0.25:5, 1:0.25:5);
% 3. 使用 'cubic' 方法执行插值以获得平滑结果
Vq = interp3(X, Y, Z, V, Xq, Yq, Zq, 'cubic');
% 4. 可视化结果
figure;
% 绘制原始粗糙数据的切片
subplot(1, 2, 1);
slice(X, Y, Z, V, 3, 3, 3);
shading flat; % 使用平面着色强调网格单元
title('Original Coarse Data');
xlabel('X'); ylabel('Y'); zlabel('Z');
% 绘制插值后的精细数据切片
subplot(1, 2, 2);
slice(Xq, Yq, Zq, Vq, 3, 3, 3);
shading interp; % 使用插值着色以获得平滑外观
title('Cubic Interpolated Data');
xlabel('X'); ylabel('Y'); zlabel('Z');

预期输出描述:此代码生成一个包含两个子图的图形。左侧的图,即“原始粗糙数据”,显示了数据的 3D 切片视图,由于它是在稀疏的 5x5x5 网格上渲染的,所以看起来呈块状。右侧的图,“三次插值数据”,显示了相同的切片,但更平滑、更详细,展示了插值到密集 21x21x21 网格上的效果。

此示例可视化了在简单数据集上“线性”和“样条”插值之间的差异。

% 1. 创建一个带有单个“热点”的简单 3D 数据集
V = zeros(5, 5, 5);
V(3, 3, 3) = 1; % 在零值区域中有一个值为 1 的点
% 2. 使用 'linear' 方法进行插值
Vq_linear = interp3(V, 2); % 将网格细化两倍
% 3. 使用 'spline' 方法进行插值
Vq_spline = interp3(V, 2, 'spline');
% 4. 可视化结果
figure;
% 线性插值结果
subplot(1, 2, 1);
slice(Vq_linear, 9, 9, 9); % 通过细化网格的中心切片
title('Linear Interpolation');
xlabel('X'); ylabel('Y'); zlabel('Z');
% 样条插值结果
subplot(1, 2, 2);
slice(Vq_spline, 9, 9, 9);
title('Spline Interpolation');
xlabel('X'); ylabel('Y'); zlabel('Z');

预期输出描述:此代码生成两个子图。左侧的“线性插值”图显示了一个金字塔状的形状,其中单个热点的影响呈线性递减。右侧的“样条插值”图显示了一个更平滑的钟形分布,说明了样条如何从热点创建更连续和流畅的过渡。

  • 方法选择:首先使用 'linear' 以获得速度和质量的良好平衡。当视觉平滑度至关重要时,使用 'cubic'、'makima' 或 'spline'。仅当您需要保留原始数据值并且不希望创建任何新值时,才使用 'nearest'。
  • 性能:对大型 3D 数组进行插值计算成本很高。如果性能是问题,请考虑仅对数据的一个子集进行插值,或使用较低分辨率的查询网格。
  • 外推:当查询点 (Xq,Yq,Zq) 位于原始网格 (X,Y,Z) 边界之外时,请务必小心。interp3 默认情况下会为这些点返回 NaN(非数字)。您可以提供一个可选的第五个参数,为外推点指定一个常数值,例如 interp3(..., 'linear', 0),以便对网格外的点返回 0。