使用numpy.reshape()反转skimage view_as_blocks()

3
我想将一个包含 2 个通道的 4x4 图像划分为多个不重叠的正方形,然后重新构建图片。
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]]]])

在使用reshape()之前,我尝试了多个.swapaxes(),但就是无法使其起作用。


尝试使用reshape、transpose(或swap)和reshape的组合,例如arr1.reshape(2,2,2,2,2).transpose(0,1,3,2,4).reshape(2,4,4) - hpaulj
你在两个 reshape 之间做什么?避免这些可能就像使用 np.ndindex 作为 for 循环迭代器而不是循环遍历第一个维度一样简单。 - Daniel F
@hpaulj:我尝试了几个变体,但是经过多次尝试仍然找不到正确的答案。 - gaussit
@DanielF:我正在使用skimage将图像分割成非重叠块。 - gaussit
2个回答

2
发生的情况是,您的.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]]

我希望这能有所帮助!

感谢您的输入!我确实可以使用2D数组进行复制。然而,对于3D数组(不幸的是我需要3D数组),当重新应用view_as_blocks()时,我找不到正确的设置,数组总是混乱的... - gaussit

2
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)个窗口。也就是说,每个(4,4)子数组变成了一个(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)个窗口,然后返回。

我怀疑同样的变换也适用于更复杂的维度,但我没有时间(或兴趣)去计算细节。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接