title: Using NumPy for Fast Interpolation
body: <p>Given a masked NumPy array of dimensionality <code>(frames, points, 2)</code> representing a video of <code>frames</code> frames, where in each frame <code>points</code> <code>(x, y)</code> points are being tracked.</p>
  
  <p>I would like to interpolate this video from <code>frames</code> frames to any number of frames, very fast, hopefully with a cubic spline, but any other continuous interpolation will work OK too.</p>
  
  <hr>
  
  <p>The naive solution I have implemented splits the array into 2 arrays of dimensions <code>(frames, points)</code> for the <code>X</code> array and <code>Y</code> array.
  Then, I transpose the array to <code>(points, frames)</code>. For each row (single point over-time) I map it to an index and value, so the array <code>[5, 6, --, 7]</code> becomes:</p>
  
  <p><code>[{"x": 0, "y": 5}, {"x": 1, "y": 6}, {"x": 3, "y": 7}]</code></p>
  
  <p>I feed this to a <code>scipy.interp1d</code>, and run on my new array which is for example <code>[0, 0.5, 1, 1.5, 2, 2.5, 3]</code> and get a new <code>x, y</code> array that I then convert back to NumPy.</p>
  
  <p>This process removes the masks for intermittent frames (which is fine with me).</p>
  
  <p>Current performance: Small array of shape <code>(9 frames, 140 points, 2)</code> to <code>(24 frames, 140 points, 2)</code></p>
  
  <ul>
  <li>Cubic interpolation 0.115 seconds</li>
  <li>Linear interpolation 0.112 seconds</li>
  </ul>
  
  <hr>
  
  <h3>Note!</h3>
  
  <p>This is a masked array, like <code>[5, 6, --, 7]</code>. so it is important to incorporate the masks in the interpolation in order to not have 0 values (the data array looks like <code>[5, 6, 0, 7]</code>!</p>
  
  <p>Here is a toy example with data on the desired and undesired behaviors:</p>
  
  <pre class="lang-py prettyprint-override"><code>import numpy as np
  import numpy.ma as ma
  from scipy.interpolate import interp1d
  
  points = np.array([1, 2, 3, 4, 0, 6])
  mask = [0, 0, 0, 0, 1, 0]
  points = ma.array(points, mask=mask)
  print(points)  # [1 2 3 4 -- 6]
  
  lin = np.linspace(0, 1, 6)
  
  # Undesired behavior
  f = interp1d(lin, points, axis=0, kind='cubic')
  print(f(lin))  # [1  2 3 4 -8.8817842e-16 6]
  
  # Desired behavior
  compressed_lin = [0, 0.2, 0.4, 0.6, 1]
  compressed_points = np.array([1,2,3,4,6])
  f = interp1d(compressed_lin, compressed_points, axis=0, kind='cubic')
  print(f(lin)) # [1 2 3 4 5 6]
  </code></pre>