为什么 MATLAB interp2 在非均匀间隔样本上比 SciPy 快得多?



>我有一个图像投影问题,在最后一步中,我需要对源图像使用双线性插值到间距不均匀的目标点。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。它仍然插值到这些值。然后,这需要找到凸包并手动消除船体外部的值,这很慢。

问题是你正在使用的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 中做错了什么。

为了进行比较,您可以尝试将 for 循环添加到 MATLAB 中,看看它的性能如何。

有关想法和概念,请参阅此处或此处,

最新更新