Question

import numpy as np

data = np.array([[0, 0, 1, 1, 2, 2],
                 [1, 0, 0, 1, 2, 2],
                 [1, 0, 1, 0, 0, 0],
                 [1, 1, 0, 0, 2, 0]])

How can I do the followings?

Within 2 by 2 patch:

if any element is 2: put 2
if any element is 1: put 1
if all elements are 0: put 0

The expected result is:

np.array([[1, 1, 2],
          [1, 1, 2]])
Was it helpful?

Solution

Using extract_patches from scikit-learn you can write this as follows (copy and paste-able code):

import numpy as np
from sklearn.feature_extraction.image import extract_patches

data = np.array([[0, 0, 1, 1, 2, 2],
                 [1, 0, 0, 1, 2, 2],
                 [1, 0, 1, 0, 0, 0],
                 [1, 1, 0, 0, 2, 0]])

patches = extract_patches(data, patch_shape=(2, 2), extraction_step=(2, 2))
output = patches.max(axis=-1).max(axis=-1)

Explanation: extract_patches gives you a view on patches of your array, of size patch_shape and lying on a grid of extraction_step. The result is a 4D array where the first two axes index the patch and the last two axes index the pixels within the patch. We then evaluate the maximum over the last two axes to obtain the maximum per patch.

EDIT This is actually very much related to this question

OTHER TIPS

I'm not sure where you get your input from or where you are supposed to leave the output, but you can adapt this.

import numpy as np

data = np.array([[0, 0, 1, 1, 2, 2],
                 [1, 0, 0, 1, 2, 2],
                 [1, 0, 1, 0, 0, 0],
                 [1, 1, 0, 0, 2, 0]])

def patchValue(i,j):
    return max([data[i][j],
                data[i][j+1],
                data[i+1][j],
                data[i+1][j+1]])

result = np.array([[0, 0, 0],
                   [0, 0, 0]])

for (v,i) in enumerate(range(0,4,2)):
    for (w,j) in enumerate(range(0,6,2)):
        result[v][w] = patchValue(i,j)

print(result)

Here's a rather lengthy one-liner that relies solely on reshaping, transposes, and taking maximums along different axes. It is fairly fast too.

data.reshape((-1,2)).max(axis=1).reshape((data.shape[0],-1)).T.reshape((-1,2)).max(axis=1).reshape((data.shape[1]/2,data.shape[0]/2)).T

Essentially what this does is reshape to take the maximum in pairs of two horizontally, then shuffle things around again and take the maximum in pairs of two vertically, ultimately giving the maximum of each block of 4, matching your desired output.

If the original array is large, and performance is an issue, the loops can be pushed down to numpy C code by manipulating the shape and strides of the original array to create the windows that you are acting on:

import numpy as np
from numpy.lib.stride_tricks import as_strided

data = np.array([[0, 0, 1, 1, 2, 2],
                 [1, 0, 0, 1, 2, 2],
                 [1, 0, 1, 0, 0, 0],
                 [1, 1, 0, 0, 2, 0]])

patch_shape = (2,2)
data_shape = np.array(data.shape)

# transform data to a 2x3 array of 2x2 patches/windows

# final shape of the computation on the windows can be calculated with:
# tuple(((data_shape-patch_shape) // patch_shape) + 1)
final_shape = (2,3)

# the shape of the windowed array can be calculated with:
# final_shape + patch_shape
newshape = (2, 3, 2, 2)

# the strides of the windowed array can be calculated with:
# tuple(np.array(data.strides) * patch_shape) + data.strides
newstrides = (48, 8, 24, 4)

# use as_strided to 'transform' the array
patch_array = as_strided(data, shape = newshape, strides = newstrides)

# flatten the windowed array for iteration - dim of 6x2x2
# the number of windows is the product of the 'first' dimensions of the array
# which can be calculated with:
# (np.product(newshape[:-len(patch_shape)])) + (newshape[-len(patch_array):])
dim = (6,2,2)

patch_array = patch_array.reshape(dim)

# perfom computations on the windows and reshape to final dimensions
result = [2 if np.any(patch == 2) else
          1 if np.any(patch == 1) else
          0 for patch in patch_array]
result = np.array(result).reshape(final_shape)

A generalized 1-d function for creating the windowed array can be found at Efficient rolling statistics with NumPy

A generalised multi-dimension function and a nice explanation can be found at Efficient Overlapping Windows with Numpy

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top