scipy 和 pytorch 中三次二维插值方法的区别

问题描述 投票:0回答:1

SciPy 和 PyTorch 都有多种插值 2D 图像的方法。然而,对于三次插值,它们似乎没有做同样的事情。为什么他们如此不同?

到目前为止,我发现以下内容似乎在

order=1
/
mode=linear
/
mode=bilinear
(最多浮点错误)执行相同的操作:

  • scipy.interpolate.interpn
  • scipy.ndimage.map_coordinates
  • torch.nn.functional.interpolate
    align_corners=True
  • torch.nn.functional.grid_sample
    align_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 阶的可视化绝对差异:

python numpy pytorch scipy interpolation
1个回答
0
投票

(部分答案)interpn(这是RegularGridInterpolator的便捷包装器)和ndimage.map_coordinates之间的区别在于后者假设等距整数值网格,而前者允许更通用的网格间距(仍然是规则的,但可以在维度之间变化) 。这是 scipy 文档中的一个示例:

https://docs.scipy.org/doc/scipy/tutorial/interpolate/ND_regular_grid.html

© www.soinside.com 2019 - 2024. All rights reserved.