如何 deform/scale 一维的 3 维 numpy 数组?

How to deform/scale a 3 dimensional numpy array in one dimension?

我想deform/scale一个一维的三维numpy数组。我将在 2D 中可视化我的问题:

我有原始图像,它是一个二维 numpy 数组:

然后我想 deform/scale 它用于维度 0 或水平维度中的某些因素:

对于 PIL images, there are a lot of solutions, for example in pytorch,但是如果我有一个 numpy 形状数组 (w, h, d) = (288, 288, 468) 怎么办?我想以 1.04 的因子对宽度进行上采样,例如,到 (299, 288, 468)。每个单元格包含一个介于 0 和 1 之间的标准化数字。

我不确定,如果我只是没有在寻找正确的词汇,如果我尝试在线搜索。因此,纠正我的问题也会有所帮助。或者告诉我这个问题的数学背景,我可以自己写代码。

谢谢!

您可以沿特定轴重复数组的次数等于 ceil(factor),其中 factor > 1 然后在拉伸维度上均匀 space 索引到 select int(factor * old_length) 个元素。这不执行任何类型的插值,而只是重复一些元素:

import math

import cv2
import numpy as np
from scipy.ndimage import imread

img = imread('/tmp/example.png')
print(img.shape)  # (512, 512)

axis = 1
factor = 1.25

stretched = np.repeat(img, math.ceil(factor), axis=axis)
print(stretched.shape)  # (512, 1024)

indices = np.linspace(0, stretched.shape[axis] - 1, int(img.shape[axis] * factor))
indices = np.rint(indices).astype(int)

result = np.take(stretched, indices, axis=axis)
print(result.shape)  # (512, 640)

cv2.imwrite('/tmp/stretched.png', result)

这是结果(左边是原来的example.png,右边是stretched.png):

这是使用 scipy.interpolate 对 3D 图像进行线性上采样的示例,希望对您有所帮助。

(我在这里用 np.meshgrid 工作了很多,如果你不熟悉它,我最近解释了它

import numpy as np
import matplotlib.pyplot as plt

import scipy
from scipy.interpolate import RegularGridInterpolator

# should be 1.3.0
print(scipy.__version__)

# =============================================================================
# producing a test image "image3D"
# =============================================================================

def some_function(x,y,z):
    # output is a 3D Gaussian with some periodic modification
    # its only for testing so this part is not impotent
    out = np.sin(2*np.pi*x)*np.cos(np.pi*y)*np.cos(4*np.pi*z)*np.exp(-(x**2+y**2+z**2))
    return out


# define a grid to evaluate the function on.
# the dimension of the 3D-Image will be (20,20,20)
N = 20
x = np.linspace(-1,1,N)
y = np.linspace(-1,1,N)
z = np.linspace(-1,1,N)
xx, yy, zz = np.meshgrid(x,y,z,indexing ='ij')

image3D = some_function(xx,yy,zz)

# =============================================================================
# plot the testimage "image3D"
# you will see 5 images that corresponds to the slicing of the 
# z-axis similar to your example picture_
# https://sites.google.com/site/linhvtlam2/fl7_ctslices.jpg
# =============================================================================

def plot_slices(image_3d):
    f, loax = plt.subplots(1,5,figsize=(15,5))    
    loax = loax.flatten()
    for ii,i in enumerate([8,9,10,11,12]):
        loax[ii].imshow(image_3d[:,:,i],vmin=image_3d.min(),vmax=image_3d.max())
    plt.show()

plot_slices(image3D)

# =============================================================================
# interpolate the image
# =============================================================================

interpolation_function = RegularGridInterpolator((x, y, z), image3D, method = 'linear')

# =============================================================================
# evaluate at new grid
# =============================================================================

# create the new grid that you want
x_new = np.linspace(-1,1,30)
y_new = np.linspace(-1,1,40)
z_new = np.linspace(-1,1,N)
xx_new, yy_new, zz_new = np.meshgrid(x_new,y_new,z_new,indexing ='ij')

# change the order of the points to match the input shape of the interpolation
# function. That's a bit messy but i couldn't figure out a way around that
evaluation_points = np.rollaxis(np.array([xx_new,yy_new,zz_new]),0,4)

interpolated = interpolation_function(evaluation_points)

plot_slices(interpolated)

原始(20,20,20)维3D图像:

以及上采样的 (30,40,20) 维 3D 图像:

看起来就像使用 pytorch 中的 torch.nn.functional.interpolate 函数并选择 'trilinear' 作为插值模式一样简单:

import torch

PET = torch.tensor(data)

print("Old shape = {}".format(PET.shape))

scale_factor_x = 1.4

# Scaling.
PET = torch.nn.functional.interpolate(PET.unsqueeze(0).unsqueeze(0),\
 scale_factor=(scale_factor_x, 1, 1), mode='trilinear').squeeze().squeeze()

print("New shape = {}".format(PET.shape))

输出:

>>> Old shape = torch.Size([288, 288, 468])
>>> New shape = torch.Size([403, 288, 468])

我通过查看数据验证了结果,但由于数据隐私,我不能在这里展示它们。抱歉!