【问题标题】:Why is MATLAB interp2 Much Faster Than SciPy on Non-Uniformly Spaced Samples?为什么 MATLAB interp2 在非均匀间隔样本上比 SciPy 快得多?
【发布时间】:2019-10-19 12:15:45
【问题描述】:

我有一个图像投影问题,在最后一步中,我需要对源图像使用双线性插值到非均匀间隔的目标点。 MATLAB 可以很好地处理这个问题,并使用 interp2 非常快速地计算出答案。 MATLAB 示例:

img = imread('ngc6543a.jpg');
img = double(rgb2gray(img)) / 256;
[img_col, img_row] = meshgrid(1:size(img, 2), 1:size(img, 1));
interp_rows = 325+200*randn(1, 100000);
interp_cols = 300*200*randn(1, 100000);

tic
img_interp = interp2(img_col, img_row, omg, interp_rows, interp_cols)
toc
>Elapsed time is 0.011680 seconds.

据我所知,没有办法在 Python 中以几乎一样快的速度对非均匀采样点进行插值。所有典型的 SciPy 方法似乎都希望目标是等距点的 2D 网格,而不是点的随机分散。 (例如scipy.interpolate.interp2d)。在 SciPy 中执行相同的操作需要一个 for 循环:

from scipy.interpolate import interp2d
import numpy as np


% Does NOT interpolate to points outside the convex hull (which is good)
interpolator = interp2d(img_col, img_row, img)
interp_rows = 325+200*np.random.randn(1, 100000);
interp_cols = 300*200*np.random.randn(1, 100000);

result = np.empty((100000,), dtype=np.float)
for i in range(100000):
    result[i] = interpolator(interp_cols[i], interp_rows[i])

正如人们对循环所期望的那样,这需要非常长的时间。我相信一定有更好的方法。我找到的最接近的是scipy.interpolate.RectBivariateSpline。有了这个,我可以几乎以与 MATLAB 几乎相同的速度做我想做的事:

from scipy.interpolate import RectBivariateSpline

% DOES interpolate to points outside the convex hull (which is bad)
interpolator = RectBivariateSpline(img_col, img_row, img)
img_interp = interpolator(interp_cols, interp_rows, grid=False)

这种方法的问题在于它没有将源凸包之外的值设置为 NaN。它仍然插值到这些值。然后,这需要找到凸包并手动消除凸包之外的值,这很慢。

【问题讨论】:

  • 这里有很多关于 Python 比 MATLAB 慢的问题。 Python 是免费的,MATLAB 不是。您可以选择便宜或快速。
  • 这根本不是真的。通常人们只是不知道如何用 Python 编写快速代码 :)
  • “这个方法的问题是它不会将源凸包之外的值设置为 NaN。它仍然会插值到这些值。”源(图像)的凸包是一个矩形(或者我错过了什么)?
  • @CrisLuengo,主要问题是我觉得我一定错过了一些东西。看来 Python 必须有一个同样快速的方法。
  • @Trilarion,在这个组成的例子中,源图像的凸包是一个矩形。不一定总是如此。此外,目标点可能在该形状之外。

标签: python matlab image-processing scipy interpolation


【解决方案1】:

问题在于您使用的 for 循环:

for i in range(100000):
    result[i] = interpolator(interp_cols[i], interp_rows[i])

使用 MATLAB 代码,您正在使用矢量化方法:

img_interp = interp2(img_col, img_row, omg, interp_rows, interp_cols)

scipy 也是如此:

result = interpolator(interp_cols, interp_rows)

这应该会给你一个很好的加速。

避免在 Python 中使用 for 循环。通常在 Numpy / Scipy 中有一个矢量化的方法。

MATLAB 可能仍然稍微快一些,但是当您看到计算时间可能慢 2 到 100 倍时,说明您在 Python 中做错了。

为了比较,您可以尝试在 MATLAB 中添加 for 循环,看看效果如何。

有关想法和概念,请参阅 herehere

【讨论】:

  • 另外,numpy 的“标准”安装可能是单线程的,而 MATLAB 对这些操作有非常高效的多核实现。在我的 64 核机器上,我可以看到 MATLAB 将它们全部用于每个简单的向量运算,而 numpy 没有。也就是说,是的,矢量化可能是这里的主要因素。
  • numpy 中的一些操作在后台是并行的。参见例如scipy.github.io/old-wiki/pages/ParallelProgrammingquora.com/…
  • 不幸的是,SciPy 插值器的问题在于它不接受分散的输入点。它只接受输入点的范围。基本上,目标点必须是一个网格,不能像在 MATLAB 中那样随机散布。
  • MATLAB interp2d 也只接受网格数据:“interp2 Interpolation for 2-D gridded data in meshgrid format”
  • 但是 scipy 中还有其他插值函数允许分散数据:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2013-09-08
  • 1970-01-01
  • 1970-01-01
  • 2014-08-22
  • 2016-12-26
相关资源
最近更新 更多