Moving window with complete boundary in Python I asked this question a few days ago. The question is about producing moving/rolling windows of an array in Python as in the following example:

from skimage.util import view_as_windows
view_as_windows(np.arange(10*10).reshape(10,10), (4,4),4)

Out[14]:
array([[[[ 0,  1,  2,  3],
         [10, 11, 12, 13],
         [20, 21, 22, 23],
         [30, 31, 32, 33]],

        [[ 4,  5,  6,  7],
         [14, 15, 16, 17],
         [24, 25, 26, 27],
         [34, 35, 36, 37]]],


       [[[40, 41, 42, 43],
         [50, 51, 52, 53],
         [60, 61, 62, 63],
         [70, 71, 72, 73]],

        [[44, 45, 46, 47],
         [54, 55, 56, 57],
         [64, 65, 66, 67],
         [74, 75, 76, 77]]]]). 


However, this removes elements of the original arrays that don't fit into another window. It was suggested that I should fill the arrays with zeros in order to get a full window, so I wrote the following code for doing so and I thought it would be nice to have a review in case I missed corner cases:

import numpy as np

def extend_image(image, steps=16):
    # Required number of rows
    required_rows = np.mod(image.shape[0], steps)
    # Required number of columns
    required_cols = np.mod(image.shape[1], steps) 
    # Concatenate original array with rows filled with zeros 
    partial = np.concatenate((image, np.zeros((required_rows,image.shape[1])))) 
    # Concatenate partial array with columns filled with zeros
    extended = np.concatenate((partial, np.zeros((partial.shape[0], required_cols))), axis=1) 
    return extended


This should work as follows:

view_as_windows(extend_image(np.arange(10*10).reshape(10,10), steps=4), (4,4),4)

array([[[[  0.,   1.,   2.,   3.],
         [ 10.,  11.,  12.,  13.],
         [ 20.,  21.,  22.,  23.],
         [ 30.,  31.,  32.,  33.]],

        [[  4.,   5.,   6.,   7.],
         [ 14.,  15.,  16.,  17.],
         [ 24.,  25.,  26.,  27.],
         [ 34.,  35.,  36.,  37.]],

        [[  8.,   9.,   0.,   0.],
         [ 18.,  19.,   0.,   0.],
         [ 28.,  29.,   0.,   0.],
         [ 38.,  39.,   0.,   0.]]],


       [[[ 40.,  41.,  42.,  43.],
         [ 50.,  51.,  52.,  53.],
         [ 60.,  61.,  62.,  63.],
         [ 70.,  71.,  72.,  73.]],

        [[ 44.,  45.,  46.,  47.],
         [ 54.,  55.,  56.,  57.],
         [ 64.,  65.,  66.,  67.],
         [ 74.,  75.,  76.,  77.]],

        [[ 48.,  49.,   0.,   0.],
         [ 58.,  59.,   0.,   0.],
         [ 68.,  69.,   0.,   0.],
         [ 78.,  79.,   0.,   0.]]],


       [[[ 80.,  81.,  82.,  83.],
         [ 90.,  91.,  92.,  93.],
         [  0.,   0.,   0.,   0.],
         [  0.,   0.,   0.,   0.]],

        [[ 84.,  85.,  86.,  87.],
         [ 94.,  95.,  96.,  97.],
         [  0.,   0.,   0.,   0.],
         [  0.,   0.,   0.,   0.]],

        [[ 88.,  89.,   0.,   0.],
         [ 98.,  99.,   0.,   0.],
         [  0.,   0.,   0.,   0.],
         [  0.,   0.,   0.,   0.]]]])
numpy has a pad function.  It has many options, but this extends your array from a (10,10) to (12,12), which can be partitioned a 3x3 set of (4,4) windows.

np.pad(A,((0,2),(0,2)),mode='constant',constant_values=0)

array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  0,  0],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29,  0,  0],
       [30, 31, 32, 33, 34, 35, 36, 37, 38, 39,  0,  0],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49,  0,  0],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59,  0,  0],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69,  0,  0],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79,  0,  0],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89,  0,  0],
       [90, 91, 92, 93, 94, 95, 96, 97, 98, 99,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0]])


Your 'extend' returns a (20,20) array.  extend_image(A,steps=12).astype(int)[:12,:12] produces the same (12,12).  It is faster than np.pad (by about 30%).

numpy/lib/arraypad.py contains pad and the functions it uses, it you want to learn from it.  Looks like it uses np.concatenate.

In this case of just padding with 0s, here's an even faster (but not as general) a solution:

def foo(A,step=2):
    shape=(A.shape[0]+step,A.shape[1]+step)
    A1=np.zeros(shape, A.dtype)
    A1[:A.shape[0], :A.shape[1]] = A
    return A1