Измените размер массива 256x256x256 numpy на массив 64x64x64 numpy. Я пытаюсь реализовать размер окна 4, чтобы усреднить элементы - PullRequest
1 голос
/ 18 июня 2020

У меня есть разреженный массив 3D NumPy (256x256x256), размер которого я хочу изменить до 64x64x64, используя среднее значение скользящего окна. Каков был бы самый чистый способ решения этой проблемы? Стоит ли рассматривать окно усреднения 3D 4x4x4 для решения проблемы?

Я начал с окна 1D, как показано ниже, но как мне эффективно расширить до 2D или 3D?

def avgWindow(arr, size):
    return (arr[(n-1):] + arr[:-(n-1)])/float(size)

Ответы [ 4 ]

2 голосов
/ 18 июня 2020

Вы можете использовать scipy.signal.convolve для расчета скользящей средней и пропустить промежуточные элементы:

import numpy as np
from scipy.signal import convolve

old_shape = 256
a = np.arange(old_shape**3).reshape(old_shape, old_shape, old_shape)
new_shape = 64 # should be an integer divider of old shape
ksize = old_shape // new_shape
kernel = np.ones((ksize, ksize, ksize)) / (ksize**3)
res = convolve(a, kernel, 'valid')[::ksize,::ksize,::ksize]
2 голосов
/ 18 июня 2020

Вы ищете свертку только на неперекрывающихся субматрицах размера (4,4,4). Вот как вы это делаете (вероятно, самый быстрый и наименее затратный по памяти, поскольку он разделяет память и не выполняет дополнительных вычислений для каких-либо ненужных подмассивов):

from skimage.util.shape import view_as_windows
kernel = np.ones((4,4,4))
sub_matrices = view_as_windows(arr, kernel.shape, kernel.shape)
#Do convolution on extracted non-overlapping sub-matrices of shape (4,4,4)
output = np.einsum('ijk,mnlijk->mnl',kernel,sub_matrices)

Если вы не используете wi sh чтобы увеличить результат до суммы точек в ядре, просто разделите output на kernel.size (т.е. output/=kernel.size)

пример:

arr=np.ones((256,256,256))

output.shape:

(64, 64, 64)
2 голосов
/ 18 июня 2020

Если вы хотите объединить свои данные в более грубое разрешение, попробуйте сделать это с помощью np.reshape и np.mean по каждому измерению отдельно:

A = np.array([.....])
s = A.shape  # (256, 256, 256)
B = A.copy()  # be sure to save original data

# reshape last dimension into new dim and bin-size (int div for index & shape)
B = B.reshape(s[0], s[1], s[2] // 4, 4)
B = np.mean(B, axis=-1)  # computes average along last dim
B.shape # (256, 256, 64)
... # repeat for other 2 dimensions.

Это должно быть достаточно быстро, поскольку вы используете numpys внутренняя векторизация.

Добавить:

Я не эксперт с разреженными матрицами, но если это действительно спарринг, то может быть полезно взглянуть на scipy. разреженный .

1 голос
/ 18 июня 2020

Я думаю, что вы можете успешно использовать механизм объединения, например функцию, предоставляемую tensorflow (в моем случае версия 2.1), посмотрите на tf функцию пула . Таким образом, в окне размером (4,4,4) вы можете взять максимум или среднее значение.

Пример (обратите внимание, что вам следует изменить форму входной матрицы, добавив размер по оси 0):

@tf.function
def get_local_maxima(X):
    #X has shape (1, 256,256,256)
    out = tf.nn.pool(X, window_shape=(4,4,4), pooling_type='MAX', padding='VALID') 
    return out

Обратите внимание, что вы можете изменить pooling_type на 'AVG', чтобы применить среднее значение в пределах окна. Результат будет иметь форму (1, 64,64,64), поэтому вам нужно снова преобразовать форму в 3D-матрицу, вы можете просто использовать:

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