14

The question is the inverse of this question. I'm looking for a generic method to from the original big array from small arrays:

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

->

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

I am currently developing a solution, will post it when it's done, would however like to see other (better) ways.

6 Answers 6

41
import numpy as np
def blockshaped(arr, nrows, ncols):
    """
    Return an array of shape (n, nrows, ncols) where
    n * nrows * ncols = arr.size

    If arr is a 2D array, the returned array looks like n subblocks with
    each subblock preserving the "physical" layout of arr.
    """
    h, w = arr.shape
    return (arr.reshape(h//nrows, nrows, -1, ncols)
               .swapaxes(1,2)
               .reshape(-1, nrows, ncols))


def unblockshaped(arr, h, w):
    """
    Return an array of shape (h, w) where
    h * w = arr.size

    If arr is of shape (n, nrows, ncols), n sublocks of shape (nrows, ncols),
    then the returned array preserves the "physical" layout of the sublocks.
    """
    n, nrows, ncols = arr.shape
    return (arr.reshape(h//nrows, -1, nrows, ncols)
               .swapaxes(1,2)
               .reshape(h, w))

For example,

c = np.arange(24).reshape((4,6))
print(c)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]]

print(blockshaped(c, 2, 3))
# [[[ 0  1  2]
#   [ 6  7  8]]

#  [[ 3  4  5]
#   [ 9 10 11]]

#  [[12 13 14]
#   [18 19 20]]

#  [[15 16 17]
#   [21 22 23]]]

print(unblockshaped(blockshaped(c, 2, 3), 4, 6))
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]]

Note that there is also superbatfish's blockwise_view. It arranges the blocks in a different format (using more axes) but it has the advantage of (1) always returning a view and (2) being capable of handing arrays of any dimension.

Sign up to request clarification or add additional context in comments.

8 Comments

It doesn't work for c = np.arange(24).reshape((6,4)) print(unblockshaped(blockshaped(a, 3, 2), 6, 4))
blockshaped returns as expected. The problem is in unblockshaped
Yes, I had the order of arguments to reshape wrong. Try it now.
Major problem is when n * nrows * ncols = arr.size does not hold. For example, for a prime like size=17 or size=47, you can not use this method.
@SudiptaBasak: It is not a problem because there are no 2D arrays, arr, with arr.size equal to a prime number.
|
4

Yet another (simple) approach:

threedarray = ...
twodarray = np.array(map(lambda x: x.flatten(), threedarray))
print(twodarray.shape)

Comments

1

I hope I get you right, let's say we have a,b :

>>> a = np.array([[1,2] ,[3,4]])
>>> b = np.array([[5,6] ,[7,8]])
    >>> a
    array([[1, 2],
           [3, 4]])
    >>> b
    array([[5, 6],
           [7, 8]])

in order to make it one big 2d array use numpy.concatenate:

>>> c = np.concatenate((a,b), axis=1 )
>>> c
array([[1, 2, 5, 6],
       [3, 4, 7, 8]])

1 Comment

What I'm searching for i a method which can rebuild a big array (image) from smaller arrays. I need it to be generic so it can be applied to images of different sizes. Like slicing in jpeg. Slice an image to 8×8 blocks, do operations on each block, rebuild the original image from blocks.
0

It works for the images I tested for now. Will if further tests are made. It is however a solution which takes no account about speed and memory usage.

def unblockshaped(blocks, h, w):
    n, nrows, ncols = blocks.shape
    bpc = w/ncols
    bpr = h/nrows

    reconstructed = zeros((h,w))
    t = 0
    for i in arange(bpr):
        for j in arange(bpc):
            reconstructed[i*nrows:i*nrows+nrows,j*ncols:j*ncols+ncols] = blocks[t]
            t = t+1
    return reconstructed

Comments

0

Here is a solution that one can use if someone is wishing to create tiles of a matrix:

from itertools import product
import numpy as np
def tiles(arr, nrows, ncols):
    """
    If arr is a 2D array, the returned list contains nrowsXncols numpy arrays
    with each array preserving the "physical" layout of arr.

    When the array shape (rows, cols) are not divisible by (nrows, ncols) then
    some of the array dimensions can change according to numpy.array_split.

    """
    rows, cols = arr.shape
    col_arr = np.array_split(range(cols), ncols)
    row_arr = np.array_split(range(rows), nrows)
    return [arr[r[0]: r[-1]+1, c[0]: c[-1]+1]
                     for r, c in product(row_arr, col_arr)]

Comments

0

Generalized technique :

import numpy as np

arr = np.array([[[ 0,  1,  2],
                 [ 6,  7,  8]],    
                [[ 3,  4,  5],
                 [ 9, 10, 11]], 
                [[12, 13, 14],
                 [18, 19, 20]],    
                [[15, 16, 17],
                 [21, 22, 23]]])
print(arr)

block_shape = (2, 3)

blockVertical =   arr.shape[0]  // block_shape[0]
blockHorizontal = arr.shape[0] //  blockVertical

reshapedArray1 = arr.reshape(blockVertical,blockHorizontal,*block_shape)

'''
[[[[ 0  1  2]
   [ 6  7  8]]

  [[ 3  4  5]
   [ 9 10 11]]]


 [[[12 13 14]
   [18 19 20]]

  [[15 16 17]
   [21 22 23]]]]
'''

reshapedArray2 = reshapedArray1.swapaxes(1,2)
'''
[[[[ 0  1  2]
   [ 3  4  5]]

  [[ 6  7  8]
   [ 9 10 11]]]


 [[[12 13 14]
   [15 16 17]]

  [[18 19 20]
   [21 22 23]]]]
'''
res = reshapedArray2.reshape(blockVertical * block_shape[0], blockHorizontal * block_shape[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]]
'''

Method 2 :

import numpy as np

arr = np.array([[[ 0,  1,  2],
                 [ 6,  7,  8]],    
                [[ 3,  4,  5],
                 [ 9, 10, 11]], 
                [[12, 13, 14],
                 [18, 19, 20]],    
                [[15, 16, 17],
                 [21, 22, 23]]])


arrTransposed = arr.reshape(2,2,2,3)
print(arrTransposed)
'''
[[[[ 0  1  2]
   [ 6  7  8]]

  [[ 3  4  5]
   [ 9 10 11]]]


 [[[12 13 14]
   [18 19 20]]

  [[15 16 17]
   [21 22 23]]]]
'''
res1 = arrTransposed.swapaxes(1,2).reshape(4,6)
print(res1)
'''

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

Method 3(Einsum) :

import numpy as np

arr = np.array([[[ 0,  1,  2],
                 [ 6,  7,  8]],    
                [[ 3,  4,  5],
                 [ 9, 10, 11]], 
                [[12, 13, 14],
                 [18, 19, 20]],    
                [[15, 16, 17],
                 [21, 22, 23]]])



# Use einsum 
result_einsum = np.einsum('abcd -> acbd', arr.reshape(2, 2, 2, 3)).reshape(4, 6)

print(result_einsum)

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

'''

Method 4 :

import numpy as np
from skimage.util import view_as_blocks

# Define the input array
arr = np.array([[[ 0,  1,  2],
                 [ 6,  7,  8]],    
                [[ 3,  4,  5],
                 [ 9, 10, 11]], 
                [[12, 13, 14],
                 [18, 19, 20]],    
                [[15, 16, 17],
                 [21, 22, 23]]])

# Specify the block shape for the 3D array
block_shape = (2,1,3)

# Use view_as_blocks to split the array into blocks
blocks = view_as_blocks(arr, block_shape)
print(blocks)
'''

[[[[ [[ 0  1  2]]

    [[ 3  4  5]]]]

  [[[[ 6  7  8]]

    [[ 9 10 11] ]]]]




 [[[[[12 13 14]]

    [[15 16 17]]]]



  [[[[18 19 20]]

    [[21 22 23]]]]]]

'''
# Reshape and rearrange the blocks into the desired 2D array
blocks_reshaped = blocks.reshape(2, 2, 2, 3)#.reshape(4, 6)

print(blocks_reshaped)
'''
[[[[ 0  1  2]
   [ 3  4  5]]

  [[ 6  7  8]
   [ 9 10 11]]]


 [[[12 13 14]
   [15 16 17]]

  [[18 19 20]
   [21 22 23]]]]

'''
res = blocks_reshaped.reshape(4,6)
print(res)
'''
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
'''

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.