skimage.measure.block_reduceс помощью лямбда-функции

#python #arrays #image-processing #lambda #scikit-image

#питон #массивы #обработка изображений #лямбда #scikit-изображение

Вопрос:

У меня есть массив:

 import numpy as np
arr = np.random.randint(0,10,size=[8,8])
 

arr является:

 array([[9, 1, 8, 2, 0, 4],
       [0, 7, 6, 9, 7, 5],
       [0, 7, 1, 6, 6, 2],
       [3, 6, 3, 3, 8, 1]])
 

Я хочу уменьшить размер этого массива с помощью skimage.measure.block_reduce . Я так и делаю

 from skimage import measure as sm
reduced_arr = sm.block_reduce(arr, block_size=(4,6), func=np.max)
 

reduced_arr является:

 array([[6, 7],
       [9, 7]])
 

Я пытаюсь добиться того же самого, используя лямбда-функцию:

 reduced_arr = sm.block_reduce(arr, block_size=(2,4), func= lambda block: np.max(block))
 

Затем я получаю сообщение об ошибке:

 ---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-115-a11dc12d3db0> in <module>()
----> 1 reduced_arr = sm.block_reduce(arr, block_size=(2,4), func= lambda block: np.max(block))

/usr/local/lib/python3.7/dist-packages/skimage/measure/block.py in block_reduce(image, block_size, func, cval, func_kwargs)
     85 
     86     return func(blocked, axis=tuple(range(image.ndim, blocked.ndim)),
---> 87                 **func_kwargs)

TypeError: <lambda>() got an unexpected keyword argument 'axis'
 

Как использовать block_reduce с лямбда-функциями?

Мой вариант использования в реальном мире сложнее, чем просто готовая функция numpy, вот почему мне это нужно.

Ответ №1:

Не уверен, что на этот вопрос все еще нужен ответ, но я видел другой, так что давайте попробуем.

Следуя документу skimage, указано, что функция, указанная в аргументе, должна «реализовывать параметр оси». Быстро ищем np.mean в документе numpy, и вы видите, что он действительно реализует параметр оси.

Поэтому в источнике самого сокращения блока параметр axis вызывается func :

 def block_reduce(image, block_size=2, func=np.sum, cval=0, func_kwargs=None):
      ...
      return func(blocked, axis=tuple(range(image.ndim, blocked.ndim)),
                         **func_kwargs)
 

При этом ваша пользовательская функция должна затем реализовать такое поведение. С быстрым исправлением ваш пример теперь будет работать правильно :

 
import numpy as np
arr = np.random.randint(0,10,size=[8,8])
arr
Out[53]: 
array([[3, 3, 2, 8, 0, 4, 2, 6],
       [8, 9, 8, 5, 1, 6, 1, 0],
       [9, 2, 6, 9, 7, 9, 1, 6],
       [3, 6, 8, 2, 8, 2, 1, 3],
       [8, 0, 3, 3, 9, 6, 5, 4],
       [5, 2, 9, 3, 8, 5, 9, 8],
       [2, 9, 0, 7, 0, 0, 5, 8],
       [6, 4, 7, 1, 9, 9, 6, 9]])

from skimage import measure as sm
reduced_arr = sm.block_reduce(arr, block_size=(4,6), func=np.max)
reduced_arr
Out[55]: 
array([[9, 6],
       [9, 9]])

reduced_arr_with_lambda = sm.block_reduce(arr, block_size=(4,6), 
                                          func= lambda block, axis: np.max(block, axis))
reduced_arr_with_lambda
Out[57]: 
array([[9, 6],
       [9, 9]])

np.testing.assert_array_equal(reduced_arr, reduced_arr_with_lambda)
 

Наконец, для более острой функции вам нужно понять, как работает ось кортежей, а для функции, отличной от numpy, реализовать способ использования axis. Честно говоря, это утомительно, поэтому мой совет — придерживаться функции numpy.