从*.nii文件加载模型:
img = nib.load(sFileName)
array = np.array(img.dataobj).astype("uint8") # 3d array with e.g. 0.5,0.5,2 mm
# TODO resample
img = nib.load(sFileName)
array = np.array(img.dataobj).astype("uint8") # 3d array with e.g. 0.5,0.5,2 mm
# TODO resample
这可能是最好的方法,缩放方法专门为这种任务设计。
from scipy.ndimage import zoom
new_array = zoom(array, (0.5, 0.5, 2))
按指定比例在每个维度上更改大小。如果数组的原始形状是,例如,(40, 50, 60)
,则新形状将为(20, 25, 120)
。
SciPy具有信号处理的大量方法。 最相关的是抽取(decimate)和多项式重采样(resample_poly)。 我在下面使用后者。
from scipy.signal import resample_poly
factors = [(1, 2), (1, 2), (2, 1)]
for k in range(3):
array = resample_poly(array, factors[k][0], factors[k][1], axis=k)
这些因子(必须是整数)用于上采样和下采样。具体如下:
可能的缺点是:此过程在每个维度上独立进行,因此空间结构可能不如ndimage方法考虑得那么充分。
这种方法更实用,但也更费力,并且没有滤波的好处:直接进行下采样。我们需要为插值器创建一个网格,使用每个方向上的原始步长。创建插值器后,需要在新的网格上进行评估;其调用方法使用了一种不同的网格格式,需使用 mgrid
准备。
from scipy.interpolate import RegularGridInterpolator
values = np.random.randint(0, 256, size=(40, 50, 60)).astype(np.uint8) # example
steps = [0.5, 0.5, 2.0] # original step sizes
x, y, z = [steps[k] * np.arange(values.shape[k]) for k in range(3)] # original grid
f = RegularGridInterpolator((x, y, z), values) # interpolator
dx, dy, dz = 1.0, 1.0, 1.0 # new step sizes
new_grid = np.mgrid[0:x[-1]:dx, 0:y[-1]:dy, 0:z[-1]:dz] # new grid
new_grid = np.moveaxis(new_grid, (0, 1, 2, 3), (3, 0, 1, 2)) # reorder axes for evaluation
new_values = f(new_grid)
缺点:例如,当一个维度减少2时,实际上会丢弃每个其他值,这是简单的下采样。在这种情况下,理想情况下应该平均相邻的值。在信号处理方面,在decimation之前进行低通滤波。
import torchio as tio
image = tio.ScalarImage(sFileName)
resample = tio.Resample(1)
resampled = resample(image)
resample = tio.Resample(1, image_interpolation='bspline')
。 - fepegar最佳现代解决方案必须包括使用Python的ITK库。
我假设您的数据已针对每个对象进行二值化处理!如果您正在处理颜色甚至灰度图像,则应该使用深度神经网络,但这超出了范围。
我会使用ITK的morphological interpolation extension。您需要手动添加每个图像平面之间的间距。因此,假设您的XYZ比例为1:1:7,请在每个图像平面之间添加7个空白平面,并将新矩阵用作函数的主要参数。
确保遵守库支持的dtype
。我使用np.uint8
作为我的数组dtype
。
from typing import Union
import itk
import numpy as np
from yaspin import yaspin
from yaspin.spinners import Spinners
INTERPOLATION_TEXT = "Interpolating for the first time"
@yaspin(Spinners.bouncingBall, text=INTERPOLATION_TEXT)
def morphological_interpolation(
labeled_stack: np.ndarray, stack_depth_spacing: Union[float, int]
):
spacing_array = np.zeros(
(round(stack_depth_spacing), *labeled_stack.shape[1:]),
dtype=labeled_stack.dtype,
)
spaced_stack = []
for xy_plane in labeled_stack:
spaced_stack.append(np.expand_dims(xy_plane, axis=0))
spaced_stack.append(spacing_array)
spaced_stack.pop(-1)
spaced_stack = np.concatenate(spaced_stack)
spaced_stack.astype(labeled_stack.dtype, copy=False)
return itk.GetArrayFromImage(
itk.morphological_contour_interpolator(itk.GetImageFromArray(spaced_stack))
)
spacing = (1,1,1)
import ants
img = ants.image_read(file)
filin = ants.resample_image(img,spacing,False,1)
ants.image_write(filin,output)
我在torch.nn.functional
中使用grid_sample
。当您想要在非均匀分布点上重新采样3D数组时,它非常方便。
以下是示例代码。您可以通过更改代码中的grid
来指定重新采样点。
import numpy as np
import torch
import torch.nn.functional as F
def resize_by_grid_sample(x):
dx = torch.linspace(-1, 1, 8)
dy = torch.linspace(-1, 1, 32)
dz = torch.linspace(-1, 1, 32)
meshx, meshy, meshz = torch.meshgrid((dx, dy, dz))
grid = torch.stack((meshx, meshy, meshz), 3)
grid = grid.unsqueeze(0)
x = x[np.newaxis, np.newaxis, :, :, :]
x = torch.tensor(x, requires_grad=False)
out = F.grid_sample(x, grid, align_corners=True)
out = out.data.numpy()
out = np.squeeze(out)
return out
data = np.random.normal(size=(32,32,32)).astype(np.float32)
# grid_sample
resized_data = resize_by_grid_sample(data)
align_corners=True
和align_corners=False
之间的区别在于调整大小之前和之后是否对齐角像素,这是一个很好的示意图 nice figure here。
scipy.interpolate.RegularGridInterpolator
可能适用于您的情况。 - Paul Brodersen