numpy scipy和pytorch中三次二维插值方法的差异

zy1mlcev  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(98)

SciPy和PyTorch都有多种插值2D图像的方法。然而,对于三次插值,它们似乎没有做同样的事情。为什么它们如此不同?
到目前为止,我发现下面的代码似乎在order=1/mode=linear/mode=bilinear上做同样的事情(直到浮点错误):

  • scipy.interpolate.interpn
  • scipy.ndimage.map_coordinates
  • torch.nn.functional.interpolatealign_corners=True
  • torch.nn.functional.grid_samplealign_corners=True

然而,在顺序3中,它们都彼此不同。
由于有这么多不同的功能,我将接受部分答案,解释其中一些之间的差异。
这是一个(尝试的)最小示例(仍然很长)。这个例子只是简单地使用插值方法对随机图像进行上采样。

# Computations
import numpy as np
import numpy.typing
import torch
from scipy.interpolate import interpn
from scipy.ndimage import map_coordinates
from torch.nn.functional import interpolate, grid_sample

# Visualizations
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm

def get_interpolated_values(
    original_size: tuple[int, int],
    sample_size: tuple[int, int],
    order: int,
) -> list[np.typing.NDArray], list[str]:
    '''Returns list of interpolated images with labels for which interpolation
    method was used.'''

    # Initialize source values for interpolation
    values = np.random.rand(*original_size)
    order2str = [
        'nearest',
        'linear',
        None,
        'cubic',
    ]

    # Initialize data collection
    labels = []
    interpolated_values = []

    # Scipy interpn
    labels.append('scipy.interpn')
    interpolated_values.append(
        interpn(
            points=(
                np.mgrid[0 : original_size[0]],
                np.mgrid[0 : original_size[1]],
            ),
            values=values,
            xi=np.stack(np.mgrid[
                0 : original_size[0] - 1 : sample_size[0] * 1j,
                0 : original_size[1] - 1 : sample_size[1] * 1j,
            ], axis=-1),
            method=order2str[order],
            bounds_error=True,
        )
    )

    # Scipy map_coordinates
    labels.append('scipy.map_coordinates')
    interpolated_values.append(
        map_coordinates(
            input=values,
            coordinates=np.mgrid[
                0 : original_size[0] - 1 : sample_size[0] * 1j,
                0 : original_size[1] - 1 : sample_size[1] * 1j,
            ],
            order=order,
            mode='constant',
        )
    )

    # Torch interpolate with align_corners
    value_tensor = torch.from_numpy(values)[None, None, ...]
    labels.append('torch.interpolate')
    interpolated_values.append(
        interpolate(
            input=value_tensor,
            size=sample_size,
            align_corners=True,
            mode="bi" + order2str[order],
        ).squeeze().numpy()
    )

    # Torch grid sample with corners
    labels.append('torch.grid_sample')
    interpolated_values.append(
        grid_sample(
            input=value_tensor,
            grid=torch.from_numpy(
                np.mgrid[
                    -1 : 1 : sample_size[0] * 1j,
                    -1 : 1 : sample_size[1] * 1j,
                ],
            ).moveaxis(0, -1).unsqueeze(0).flip(-1),
            padding_mode='zeros',
            mode="bi" + order2str[order],
            align_corners=True,
        ).squeeze().numpy()
    )

    return interpolated_values, labels

def visualize(interpolated_values, labels):

    # Visualize each interpolated result
    fig, ax_row = plt.subplots(1, len(interpolated_values))
    for i_ax, ax in enumerate(ax_row):
        ax.set_title(labels[i_ax])
        im = ax.imshow(interpolated_values[i_ax], vmin=0, vmax=1)
    plt.colorbar(im)

    # Visualise differences between methods
    fig, ax_grid = plt.subplots(
        len(interpolated_values),
        len(interpolated_values),
    )
    fig.suptitle('Interpolation differences')

    for i_ax, ax_row in enumerate(ax_grid):
        for j_ax, ax in enumerate(ax_row):
            if i_ax == j_ax:
                # Add label in diagonal
                ax.text(
                    *((n - 1) / 2 for n in interpolated_values[i_ax].shape),
                    s=labels[i_ax],
                    ha='center',
                    va='center',
                )

            # Plot difference matrix with colorbar
            diff = interpolated_values[i_ax] - interpolated_values[j_ax]
            im = ax.imshow(np.abs(diff))
            plt.colorbar(im)

def main():
    interpolated_values, labels = get_interpolated_values(
        original_size = (4, 4),
        sample_size = (5, 5),
        order = 3,
    )
    visualize(interpolated_values, labels)
    plt.show()

if __name__ == "__main__":
    main()

以下是3阶的可视化绝对差:

f5emj3cl

f5emj3cl1#

(部分答案)interpn(它是RegularGridInterpolator上的一个方便的 Package 器)和www.example.com _coordinates之间的区别ndimage.map是,后者假设等距整数值网格,而前者允许更一般的网格间距(仍然规则,但可以在维度之间变化)。下面是scipy文档中的一个例子:
https://docs.scipy.org/doc/scipy/tutorial/interpolate/ND_regular_grid.html

相关问题