Использование NumPy для быстрой интерполяции - PullRequest
4 голосов
/ 19 марта 2020

С учетом маскированного NumPy массива размерности (frames, points, 2), представляющего видео с frames кадрами, где в каждом кадре отслеживаются points (x, y) точек.

Я хотел бы интерполировать это видео от frames кадров до любого количества кадров, очень быстрое, надеюсь, со сплайном cubi c, но любая другая непрерывная интерполяция тоже будет работать нормально.


Наивное решение, которое я реализовал разбивает массив на 2 массива измерений (frames, points) для массива X и массива Y. Затем я перемещаю массив в (points, frames). Для каждой строки (одной точки в течение определенного времени) я сопоставляю ее с индексом и значением, поэтому массив [5, 6, --, 7] становится:

[{"x": 0, "y": 5}, {"x": 1, "y": 6}, {"x": 3, "y": 7}]

Я передаю это scipy.interp1d и запустить мой новый массив, например, [0, 0.5, 1, 1.5, 2, 2.5, 3], и получить новый массив x, y, который я затем преобразую обратно в NumPy.

. Этот процесс удаляет маски для прерывистых кадров (что нормально со мной).

Текущая производительность: небольшой массив формы (9 frames, 140 points, 2) до (24 frames, 140 points, 2)

  • Кубический c интерполяция 0,115 секунд
  • Линейная интерполяция 0,112 секунд

Примечание!

Это замаскированный массив, например [5, 6, --, 7]. поэтому важно включить маски в интерполяцию, чтобы не иметь нулевых значений (массив данных выглядит как [5, 6, 0, 7]!

Вот пример игрушки с данными о желаемом и нежелательном поведении:

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]

Ответы [ 2 ]

2 голосов
/ 19 марта 2020

Я не уверен, что вы используете scipy.interpolate.interp1d, как я, но мой компьютер показывает примерно 662 µs:

np.random.seed(1)
points = np.random.rand(9,140,2)

f = interp1d(np.linspace(0,1,9), points, axis=0, kind='cubic')
f(np.linspace(0,1,24))

Производительность (timeit -n 100):

662 µs ± 111 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
0 голосов
/ 20 марта 2020

Если вам это нужно быстро, 1) избегайте замаскированных массивов, 2) избегайте interp1d. Если CubicSpline недостаточно быстр, вы можете закодировать свою собственную интерполяцию cubi c, учитывая, что ваши точки равноудалены.

EDIT: если вы действительно не можете избежать маскированных массивов, остерегайтесь ничего в scipy.interpolate numpy .ma-осведомлен, так что вам нужно сделать DIY. В качестве альтернативы, рассмотрите возможность ввода данных для заполнения маскированных значений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...