Извлечение индексов двумерного двоичного массива

У меня есть массив Numpy (данные), состоящий из 0 и 1.

import numpy as np

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

Я хочу извлечь индексы, где "1" окружен соседними элементами 5*5, состоящими из 1.

Ожидаемый индекс показан звездочками, т. Е. (3,3). Ответ в виде логического массива тоже в порядке.

[[False False False False False False]
 [False False False False False False]
 [False False **True** False False False]
 [False False False False False False]
 [False False False False False False]
 [False False False False False False]]

Я пробовал как

from scipy.ndimage.morphology import binary_erosion


kernel = np.ones((5,5))

result = binary_erosion(data, kernel)
print result

[[False False False False False False]
 [False False False False False False]
 [False False  True False False False]
 [False False  True False False False]
 [False False False False False False]
 [False False False False False False]]

Это произвело две "Истинные" позиции, но я хочу только одну в (3,3).

Как это сделать?

РЕДАКТИРОВАТЬ: Решение показано в связанном вопросе тоже дает неожиданный ответ.

2 ответа

Решение

В качестве альтернативы binary_erosionВы могли бы использовать scipy.ndimage.generic_filter для достижения этой цели,

from scipy.ndimage import generic_filter
generic_filter(data, np.all, size=(5,5), mode='constant', cval=0).astype(np.bool)

Однако вы получите те же результаты, что и выше,

array([[0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0],
       [0, 0, 1, 0, 0, 0],
       [0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0]])  # using 1, 0 instead of True, False for readability

потому что это правильный ответ на ваш вопрос. 6 строк в вашем примере матрицы симметричны, и с данным ядром, будет 2 симметричных True элемент в результате.

Если вы хотите избежать этого, вы можете использовать размер не симметричного ядра: size=(6,5), хотя это создает один истинный элемент в строке 3, а не в строке 2. Это можно исправить, добавив вручную kernel массив с нулями при использовании binary_erosion,

Другой подход похож на @rth

Как ваши данные сделаны из 1 а также 0 Вы можете положить его в int массив и использовать uniform_filter добиться того же:

>>> mask = uniform_filter(data, 5, mode='constant')
>>> mask
array([[0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0],
       [0, 0, 1, 0, 0, 0],
       [0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0]])

Среднее число тех, кто не окружен, меньше чем 1 и округляется до 0 так как это целочисленный массив.

Чтобы получить первый индекс, вы можете сделать что-то вроде:

>>> y, x = np.where(mask)
>>> y[0], x[0]
(2, 2)
Другие вопросы по тегам