【问题标题】:How to deform/scale a 3 dimensional numpy array in one dimension?如何在一维中变形/缩放 3 维 numpy 数组?
【发布时间】:2019-07-31 14:28:02
【问题描述】:

我想在一维中变形/缩放 三维 numpy 数组。我将在 2D 中可视化我的问题:

我有原始图像,它是一个 2D numpy 数组:

然后我想将它变形/缩放到维度 0 或水平维度中的某个因素:

对于PIL 图像,有很多解决方案,例如在pytorch 中,但是如果我有一个 numpy 形状数组 (w, h, d) = (288, 288, 468) 怎么办?我想以 1.04 的因子对宽度进行上采样,例如到 (299, 288, 468)。每个单元格包含一个介于 0 和 1 之间的标准化数字。

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

谢谢!

【问题讨论】:

  • 问题是你要添加的值会发生什么?例如,如果您想将形状 (100,200,50) 的数组“拉伸”到 (100,300,50) 之间的值(现在有更多数字)应该是什么样子?可能您正在寻找插值,因此您可以使用众多库之一,例如 scipy。
  • 好问题,我想我必须尝试不同的可能性。我需要这个用于医疗数据,即 PET/PSMA。我不知道是什么让数据保持真实。
  • 是的,这是一个非常关键的应用程序......如果它只是关于视觉检查,我猜双三次插值可能对你有用(只要你只是将尺寸稍微改变为原始尺寸的 20% 左右) .您能给我们提供与您正在使用的数据相似的示例数据吗?
  • 示例数据不易获取。也许像this 这样的东西。确实,缩放比例将是现实的。你知道任何用于 3D 插值的库吗?
  • 第三频道有什么?例如,如果您有一个 RGB 图像,您将有一个形状为 (w,h,3) 的数组,其中 w 和 h 分别是宽度和高度。现在没有真正的理由威胁是作为 3d 插值,因为颜色不必“连接”它们或多或少是独立的。因此,您会将其视为 2D 插值的 3 倍。但是在医学图像中,通道中可能隐藏了其他信息,因此这将是相关信息(如果您已经知道数据的形状)。

标签: python-3.x numpy image-processing scale scaletransform


【解决方案1】:

您可以沿特定轴重复数组的次数等于ceil(factor) 其中factor > 1,然后在拉伸维度上均匀间隔索引以选择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):

【讨论】:

    【解决方案2】:

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

    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])
    

    我通过查看数据验证了结果,但由于数据隐私,我无法在此处显示它们。对不起!

    【讨论】:

    • 优秀而干净的解决方案。这应该是选定的答案!
    【解决方案3】:

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

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

    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 图像:

    【讨论】:

      猜你喜欢
      • 2016-12-30
      • 2014-05-23
      • 2021-07-17
      • 1970-01-01
      • 2020-11-10
      • 1970-01-01
      • 2011-05-25
      • 2021-02-21
      • 1970-01-01
      相关资源
      最近更新 更多