Извлечение индексов двумерного двоичного массива
У меня есть массив 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)