Обратный скимдж view_as_blocks () с numpy .reshape () - PullRequest
1 голос
/ 23 января 2020

Я хочу разделить изображение 4х4 с 2 каналами на несколько непересекающихся квадратов.

После этого я хочу перестроить изображение.

from skimage.util import view_as_blocks

# create testM array 
array([[[[0.53258505, 0.31525832, 0.21378392, 0.5019507 ],
         [0.31612498, 0.24320562, 0.93560226, 0.08232264],
         [0.89784454, 0.12741783, 0.88049819, 0.29542855],
         [0.11336386, 0.71023215, 0.45679456, 0.2318959 ]],

        [[0.61038755, 0.74389586, 0.85199794, 0.46680889],
         [0.01701045, 0.93953861, 0.03183684, 0.00740579],
         [0.58878569, 0.71348253, 0.33221104, 0.12276253],
         [0.04026615, 0.53837528, 0.06759152, 0.27477069]]]])

# use view_as_blocks() to get "grid" image
testB = view_as_blocks(testM, block_shape=(1,2,2,2)).reshape(-1,*(1,2,2,2))

Теперь у меня есть несколько блоков этого массива размером 2x2:

array([[[[[0.53258505, 0.31525832],
          [0.31612498, 0.24320562]],

         ...

         [[0.33221104, 0.12276253],
          [0.06759152, 0.27477069]]]]])


Однако, Я не могу изменить его прежнюю форму :

testB.reshape(1,2,4,4)

Приводит к этому. Каждый «блок» просто добавляется одно значение за другим, но не рассматривается как блок.

array([[[[0.53258505, 0.31525832, 0.31612498, 0.24320562],
         [0.61038755, 0.74389586, 0.01701045, 0.93953861],
         [0.21378392, 0.5019507 , 0.93560226, 0.08232264],
         [0.85199794, 0.46680889, 0.03183684, 0.00740579]],

        [[0.89784454, 0.12741783, 0.11336386, 0.71023215],
         [0.58878569, 0.71348253, 0.04026615, 0.53837528],
         [0.88049819, 0.29542855, 0.45679456, 0.2318959 ],
         [0.33221104, 0.12276253, 0.06759152, 0.27477069]]]])

Я пробовал несколько .swapaxes() до использования reshape(), но просто не могу заставить его работать .

Ответы [ 2 ]

2 голосов
/ 27 января 2020
In [30]: testM=np.array([[[[0.53258505, 0.31525832, 0.21378392, 0.5019507 ], 
    ...:          [0.31612498, 0.24320562, 0.93560226, 0.08232264], 
    ...:          [0.89784454, 0.12741783, 0.88049819, 0.29542855], 
    ...:          [0.11336386, 0.71023215, 0.45679456, 0.2318959 ]], 
    ...:  
    ...:         [[0.61038755, 0.74389586, 0.85199794, 0.46680889], 
    ...:          [0.01701045, 0.93953861, 0.03183684, 0.00740579], 
    ...:          [0.58878569, 0.71348253, 0.33221104, 0.12276253], 
    ...:          [0.04026615, 0.53837528, 0.06759152, 0.27477069]]]]) 
    ...:                                                                                         
In [31]: testM.shape                                                                             
Out[31]: (1, 2, 4, 4)
In [32]: from skimage.util import view_as_blocks                                                 
In [33]: testB = view_as_blocks(testM, block_shape=(1,2,2,2))                                    
In [34]: testB.shape                                                                             
Out[34]: (1, 1, 2, 2, 1, 2, 2, 2)

Это действительно та форма, которую вы хотите? В любом случае, применяя изменение формы, объединяет начальные 4 измерения:

In [36]: testB.reshape(-1,*(1,2,2,2)).shape                                                      
Out[36]: (4, 1, 2, 2, 2)

Когда я предложил

arr1.reshape(2,2,2,2,2).transpose(0,1,3,2,4).reshape(2,4,4)

, я думал, что источник с формой (2,4,4) был разделен в (2,2) windows. То есть каждый (4,4) подмассив стал массивом (2,2,2,2), массивом (2,2) (2,2) блоков. Со многими размерами размеров 2 и 4 трудно отследить, какой из них есть.

Вот преобразование, к которому я стремился:

In [62]: testM1 = testM[0,0,:,:]                                                                 
In [63]: testM1                                                                                  
Out[63]: 
array([[0.53258505, 0.31525832, 0.21378392, 0.5019507 ],
       [0.31612498, 0.24320562, 0.93560226, 0.08232264],
       [0.89784454, 0.12741783, 0.88049819, 0.29542855],
       [0.11336386, 0.71023215, 0.45679456, 0.2318959 ]])
In [64]: testB1 = view_as_blocks(testM1, block_shape=(2,2))                                      
In [65]: testB1.shape                                                                            
Out[65]: (2, 2, 2, 2)
In [66]: testB1.transpose(0,2,1,3).reshape(4,4)                                                  
Out[66]: 
array([[0.53258505, 0.31525832, 0.21378392, 0.5019507 ],
       [0.31612498, 0.24320562, 0.93560226, 0.08232264],
       [0.89784454, 0.12741783, 0.88049819, 0.29542855],
       [0.11336386, 0.71023215, 0.45679456, 0.2318959 ]])

Возьмите один (4,4) блок и разделить на (2,2,2,2) windows, а затем обратно.

Я подозреваю, что такой же тип преобразования применим к вашим более сложным измерениям, но у меня нет времени (или интереса ) проработать детали.

2 голосов
/ 24 января 2020

Происходит то, что ваши .reshape((-1, 1, 2, 2, 2)), то есть линеаризация блоков, вызывает копию:

import numpy as np
from skimage.util import view_as_blocks

arr = np.arange(24).astype(np.uint8).reshape((4, 6))
blocked = view_as_blocks(arr, (2, 3))
blocked_reshaped = blocked.reshape((-1, 2, 3))
print(arr.shape)
print(arr.strides)
print(blocked.shape)
print(blocked.strides)
print(blocked_reshaped.shape)
print(blocked_reshaped.strides)
print(np.may_share_memory(blocked, blocked_reshaped))

Результат:

(4, 6)
(6, 1)
(2, 2, 2, 3)
(12, 3, 6, 1)
(4, 2, 3)
(6, 3, 1)
False

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

block_reshaped_orig = blocked_reshaped.reshape((4, 6))
print(arr)
print(block_reshaped_orig)

Результат:

[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
[[ 0  1  2  6  7  8]
 [ 3  4  5  9 10 11]
 [12 13 14 18 19 20]
 [15 16 17 21 22 23]]

Я вижу два варианта:

  • , если вы можете избежать изменения формы и копирования, тогда ваш вызов изменения формы в конце будет работать нормально.
  • , если вам понадобится изменение формы для некоторых другой обработки, которую вы выполняете, тогда вы можете, по иронии судьбы, использовать другой вызов view_as_blocks и изменить форму, чтобы вернуть исходный порядок:
print(
    view_as_blocks(blocked_reshaped_orig, (2, 3)).reshape((4, -1))
)

Результат:

[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]

Надеюсь, это поможет!

...