Вот подход, использующий skimage.util.view_as_blocks
:
>>> import numpy as np
>>> import skimage.util as su
>>>
>>> def split_axis(N, n):
... q, r = divmod(N, n)
... left = ((np.s_[:q*n], n),) if q else ()
... right = ((np.s_[q*n:], r),) if r else ()
... return (*left, *right)
...
>>> def block_max(x, block, inplace=False):
... if not inplace:
... x = x.copy()
... xi, xj = x.shape
... bi, bj = block
... for ci, ri in split_axis(xi, bi):
... for cj, rj in split_axis(xj, bj):
... vab = su.view_as_blocks(x[ci, cj], (ri, rj))
... vab[vab < vab.max(axis=(-1, -2), keepdims=True)] = 0
... return x
...
>>> x = ([[1,2,3,4,5,6,7,8,9,10],
... [2,5,4,5,3,4,6,7,5,3],
... [3,3,4,5,6,7,3,4,5,8]])
>>>
>>> x = np.array(x)
>>>
>>> block_max(x, (2, 2))
array([[ 0, 0, 0, 0, 0, 6, 0, 8, 0, 10],
[ 0, 5, 0, 5, 0, 0, 0, 0, 0, 0],
[ 3, 3, 0, 5, 0, 7, 0, 4, 0, 8]])
Если у вас нет skimage
:
>>> def view_as_blocks(x, blockshape):
... *xs, xi, xj = x.shape
... bi, bj = blockshape
... return np.ascontiguousarray(x).reshape(*xs, xi//bi, xj//bj, *blockshape)
Ваш обновленный вопрос (без проверки):
>>> def block_max(x, block):
... out = np.zeros_like(x)
... xi, xj = x.shape
... bi, bj = block
... for ci, ri in split_axis(xi, bi):
... for cj, rj in split_axis(xj, bj):
... vab = su.view_as_blocks(x[ci, cj], (ri, rj))
... oab = su.view_as_blocks(out[ci, cj], (ri, rj))
... vmx = vab.max(axis=(-1, -2), keepdims=True)
... vmn = vab.min(axis=(-1, -2), keepdims=True)
... cond = vmx - vmn > 2
... oab[cond & (vab == vmx)] == 1
... oab[cond & (vab == vmn)] == 2
... return out