Есть ли более 1000-образный способ интерполировать мои растры? - PullRequest
0 голосов
/ 19 марта 2020

Я написал небольшую функцию для интерполяции временных последовательностей нерегулярно дискретизированных растровых изображений, чтобы они были равномерно распределены во времени (ниже). Это работает хорошо, но я просто знаю, глядя на это, что я пропускаю некоторые ярлыки. Я ищу Numpy ниндзя, чтобы дать мне такие профессиональные советы о том, как улучшить мой синтаксис, и, возможно, получить небольшое повышение производительности тоже.

Приветствия!

import numpy as np

def interp_rasters(rasters, chrons, sampleFactor = 1):
    nFrames = round(len(chrons) * sampleFactor)
    interpChrons = np.linspace(np.min(chrons), np.max(chrons), nFrames)
    frames, rows, cols, channels = rasters.shape
    interpRasters = np.zeros((nFrames, rows, cols, channels), dtype = 'uint8')
    outs = []
    for row in range(rows):
        for col in range(cols):
            for channel in range(channels):
                pixelSeries = rasters[:, row, col, channel]
                interpRasters[:, row, col, channel] = np.interp(
                    interpChrons,
                    chrons,
                    pixelSeries
                    )
    return interpRasters

1 Ответ

1 голос
/ 20 марта 2020

Поскольку значения y, которые нужно найти, должны быть 1d, я не вижу способа не перебирать np.arrays. Если растры и массивы interpRasters изменяются так, как в функции, можно использовать один l oop без явного индексирования. Это дало примерно 10% -ное улучшение скорости для моих готовых тестовых данных.

import numpy as np

frames = 10
rows = 5
cols = 10
channels = 3

np.random.seed(1234)

rasters = np.random.randint(0,256, size=(frames, rows, cols, channels))
chrons = np.random.randint(0, 256, size  = 10 )


# The original function.
def interp_rasters(rasters, chrons, sampleFactor = 1):
    nFrames = round(len(chrons) * sampleFactor)
    interpChrons = np.linspace(np.min(chrons), np.max(chrons), nFrames)
    frames, rows, cols, channels = rasters.shape
    interpRasters = np.zeros((nFrames, rows, cols, channels), dtype = 'uint8')
    outs = []
    for row in range(rows):
        for col in range(cols):
            for channel in range(channels):
                pixelSeries = rasters[:, row, col, channel]
                interpRasters[:, row, col, channel] = np.interp(
                    interpChrons,
                    chrons,
                    pixelSeries
                    )
    return interpRasters

def interp_rasters2(rasters, chrons, sampleFactor = 1):
    nFrames = round(len(chrons) * sampleFactor)
    interpChrons = np.linspace(np.min(chrons), np.max(chrons), nFrames)
    frames, rows, cols, channels = rasters.shape
    interpRasters = np.zeros((nFrames, rows, cols, channels), dtype = 'uint8')

    # Create reshaped arrays pointing to the same data 
    dat_in = rasters.reshape(frames, rows*cols*channels).T  
    # shape (r*c*c, frames)

    dat_out = interpRasters.reshape(nFrames, rows*cols*channels).T  
    # shape (r*c*c, frames)

    for pixelseries, row_out in zip(dat_in, dat_out):
        # Loop through all data in one loop.
        row_out[:] = np.interp( interpChrons, chrons, pixelseries )
    return interpRasters  
    # As dat_out and interpRasters share the same data return interpRasters

print(np.isclose(interp_rasters(rasters, chrons), interp_rasters2(rasters, chrons)).all())
# True  # The results are the same from the two functions.

%timeit interp_rasters(rasters, chrons)
# 568 µs ± 2.55 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit interp_rasters2(rasters, chrons)
# 520 µs ± 239 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Редактировать Есть также np.apply_along_axis. Это удаляет все явные циклы for, уменьшает объем кода, но медленнее, чем в предыдущих решениях.

def interp_rasters3(rasters, chrons, sampleFactor = 1):
    nFrames = round(len(chrons) * sampleFactor)
    interpChrons = np.linspace(np.min(chrons), np.max(chrons), nFrames)

    def func( arr ):  # Define the function to apply along the axis
        return np.interp( interpChrons, chrons, arr )

    return np.apply_along_axis( func, 0, rasters ).astype( np.uint8 )

print(np.isclose(interp_rasters(rasters, chrons), interp_rasters3(rasters, chrons)).all())
# True

Я думаю, что я бы лучше понял версию 3, чем версию 1 или 2, через 6 месяцев, если скорость не будет не критично

HTH

...