Создать буферную зону в массиве Numpy

У меня есть бинарное изображение следующим образом:

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

Для пикселей, имеющих значения 1, я хочу создать буферную зону из двух пикселей со значением 1, окруженную в каждых четырех направлениях. Ожидаемый результат будет следующим:

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

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


person Borys    schedule 13.03.2015    source источник
comment
Это массив только из единиц и нулей или есть другие значения?   -  person Henry Gomersall    schedule 13.03.2015
comment
да, это просто 1 и 0   -  person Borys    schedule 13.03.2015


Ответы (2)


Если у вас есть только единицы и нули во входном и выходном массиве, вы можете сделать это с помощью двумерной свертки, которая проста и работает.

from scipy.signal import convolve2d

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

# the kernel doesn't need to be ones, it just needs to be positive and
# non-zero.
kernel = np.ones((5, 5))

result = np.int64(convolve2d(data, kernel, mode='same') > 0)

Что дает вам желаемый результат. Вам нужно определить, что вы хотите сделать на краях — в этой версии выходной массив имеет тот же размер, что и входной массив.

Возможно, вы сможете сделать что-то быстрее, если у вас есть разреженный массив.

Если в вашем массиве есть значения, отличные от единицы и нуля, потребуется больше размышлений.

person Henry Gomersall    schedule 13.03.2015
comment
Зачем вам нужно положительное и ненулевое ядро? Я не вижу причин, почему, и в документации это тоже не упоминается (docs.scipy.org/doc/scipy/reference/generated/). - person Eric O Lebigot; 13.03.2015
comment
Вы не для convolve2d, но вы делаете для того, чтобы метод работал (в частности, > 0). - person Henry Gomersall; 13.03.2015
comment
@HenryGomersall Спасибо за ваш ответ. Не могли бы вы объяснить мне, почему вы использовали ядро ​​​​(5,5). - person Borys; 13.03.2015
comment
Это создает массив единиц 5x5. Вы знакомы со сверткой? Это, вероятно, немного сложно объяснить в комментарии, но, по сути, форма 5x5 — это то, что вы хотите получить на выходе для одного 1 на входе. - person Henry Gomersall; 13.03.2015
comment
Стоит отметить, что 2D-ядро разделимо, поэтому вы можете сделать это с помощью пары 1D-ядер по каждому измерению, что будет быстрее, если это проблема. - person Henry Gomersall; 13.03.2015
comment
Если скорость является проблемой, переключение на dtype=int8 как в data, так и в kernel также, вероятно, ускорит процесс по сравнению с использованием поплавков (как это делается в настоящее время). - person Eric O Lebigot; 14.03.2015
comment
@EOL можно было бы подумать, но я не могу обнаружить большой разницы, используя функцию scipy convolve2d. Это не значит, что альтернативная версия не будет лучше с другим типом. - person Henry Gomersall; 14.03.2015
comment
@HenryGomersall То же самое. Интересно! - person Eric O Lebigot; 14.03.2015

Вы также можете сделать это с помощью оператора морфологического dilation (который расширяет ones в данном случае).

from skimage.morphology import square, dilation
data = np.array([[0, 0 , 0 , 0 , 0 , 0 , 0 , 0],
                 [0, 0 , 0 , 0 , 0 , 0 , 0 , 0],
                 [0, 0 , 1 , 1 , 1 , 1 , 0 , 0],
                 [0, 0 , 1 , 1 , 1 , 1 , 0 , 0],
                 [0, 0 , 1 , 1 , 1 , 1 , 0 , 0],
                 [0, 0 , 0 , 0 , 0 , 0 , 0 , 0],
                 [0, 0 , 0 , 0 , 0 , 0 , 0 , 0]])
result = dilation(data, square(5))

Обратите внимание, что в данном случае square(5) эквивалентно np.ones((5,5)). Оператор расширения работает, расширяя True или 1 пикселей с элементом, переданным в качестве второго параметра (в данном случае квадрат 5x5 с центром в каждом пикселе).

person Imanol Luengo    schedule 08.04.2015