Reputation: 680
I have an image projection issue, where in the final step, I need to use bilinear interpolation on a source image to destination points that are non-uniformly spaced. MATLAB handles this great, and computes an answer very quickly using interp2
. MATLAB example:
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.
So far as I can tell, there is no way to interpolate to non-uniformly sampled points nearly as fast in Python. All the typical SciPy methods seem to want the target to also be a 2D grid of equally spaced points, rather than a random scatter of points. (E.g. scipy.interpolate.interp2d
). Doing this same operation in SciPy requires a for-loop:
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])
As one might expect with the loop this takes, a very long time. I am sure there must be a better way. The closest thing I have found is scipy.interpolate.RectBivariateSpline
. With this, I can almost do what I want with near the same speed as 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)
The problem with this method, is that it does not set values outside the source convex hull to NaN. It still interpolates to those values. This then requires finding the convex hull and eliminating values outside of the hull manually, which is slow.
Upvotes: 1
Views: 1008
Reputation: 7121
The problem is the for-loop you are using:
for i in range(100000):
result[i] = interpolator(interp_cols[i], interp_rows[i])
With you MATLAB code you are using a vectorized approach:
img_interp = interp2(img_col, img_row, omg, interp_rows, interp_cols)
The same is possible with scipy:
result = interpolator(interp_cols, interp_rows)
This should give you a pretty good speed-up.
Avoid for-loops in Python. Usually there is a vectorized approach in Numpy / Scipy.
MATLAB might still be slightly faster, but when you are seeing computation times that are maybe 2 to 100 times slower, you are doing something wrong in Python.
For comparison, you can try to add the for-loop to MATLAB and see how it performs.
See here or here for ideas and concepts,
Upvotes: 2