2017-01-26 6 views
1

У меня есть массив 3D numpy размером 50x50x4. У меня также есть несколько точек на плоскости 50x50. Для каждой точки мне нужно извлечь область 11x11x4, в центре которой находится точка. Эта область должна обернуться вокруг, если она пересечет границу. Каков наиболее эффективный способ сделать это, пожалуйста?Выбор нескольких патчей из массива 3D numpy

В настоящее время я использую цикл for для итерации по каждой точке, подмножества 3D-матрицы и сохранения ее в массиве pre-init. Есть ли встроенная функция numpy, которая делает это? Спасибо.


Извините за медленный отклик, большое спасибо за ваш вклад.

ответ

1

Один из подходов использовать np.pad с функциональностью wrapping вдоль последней оси. Затем мы создадим скользящие окна в этой дополненной версии с np.lib.stride_tricks.as_strided, который, будучи просмотром массива, не будет занимать больше памяти. Наконец, мы будем индексировать в скользящие окна, чтобы получить конечный результат.

# Based on http://stackoverflow.com/a/41850409/3293881 
def patchify(img, patch_shape): 
    X, Y, a = img.shape 
    x, y = patch_shape 
    shape = (X - x + 1, Y - y + 1, x, y, a) 
    X_str, Y_str, a_str = img.strides 
    strides = (X_str, Y_str, X_str, Y_str, a_str) 
    return np.lib.stride_tricks.as_strided(img, shape=shape, strides=strides) 

def sliding_patches(a, BSZ): 
    hBSZ = (BSZ-1)//2 
    a_ext = np.dstack(np.pad(a[...,i], hBSZ, 'wrap') for i in range(a.shape[2])) 
    return patchify(a_ext, (BSZ,BSZ)) 

Пример запуска -

In [51]: a = np.random.randint(0,9,(4,5,2)) # Input array 

In [52]: a[...,0] 
Out[52]: 
array([[2, 7, 5, 1, 0], 
     [4, 1, 2, 0, 7], 
     [1, 3, 0, 8, 4], 
     [8, 0, 5, 2, 7]]) 

In [53]: a[...,1] 
Out[53]: 
array([[0, 3, 3, 8, 7], 
     [3, 8, 2, 8, 2], 
     [8, 4, 3, 8, 7], 
     [6, 6, 8, 5, 5]]) 

Теперь давайте выберем одну центральную точку в a, скажем (1,0) и попытаться получить участки blocksize (BSZ) = 3 вокруг него -

In [54]: out = sliding_patches(a, BSZ=3) # Create sliding windows 

In [55]: out[1,0,...,0] # patch centered at (1,0) for slice-0 
Out[55]: 
array([[0, 2, 7], 
     [7, 4, 1], 
     [4, 1, 3]]) 

In [56]: out[1,0,...,1] # patch centered at (1,0) for slice-1 
Out[56]: 
array([[7, 0, 3], 
     [2, 3, 8], 
     [7, 8, 4]]) 

Таким образом, конечный результат для получения патчей вокруг (1,0) будет просто: out[1,0,...,:] т.е. out[1,0].

Давайте сделаем проверку формы на оригинальной профилированного массива в любом случае -

In [65]: a = np.random.randint(0,9,(50,50,4)) 

In [66]: out = sliding_patches(a, BSZ=11) 

In [67]: out[1,0].shape 
Out[67]: (11, 11, 4) 
0

В зависимости от того, сколько раз вы должны сделать это один простой и эффективный способ будет раздуть ваш исходный массив:

p = np.concatenate([a[-5:, ...], a, a[:5, ...]], axis=0) 
p = np.concatenate([p[:, -5:, :], p, p[:, :5, :]], axis=1) 

, то вы можете просто нарезать

s = p[x0 : x0 + 11, x1 : x1 + 11, :] 
Смежные вопросы