Ответ 1
Я бы сделал это так, где (a, b) - центр вашей маски:
import numpy as np
a, b = 1, 1
n = 7
r = 3
y,x = np.ogrid[-a:n-a, -b:n-b]
mask = x*x + y*y <= r*r
array = np.ones((n, n))
array[mask] = 255
У меня есть такой массив:
>>> np.ones((8,8))
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.],
[ 1., 1., 1., 1., 1., 1., 1., 1.]])
Я создаю дискообразную маску с радиусом 3 таким образом:
y,x = np.ogrid[-3: 3+1, -3: 3+1]
mask = x**2+y**2 <= 3**2
Это дает:
>> mask
array([[False, False, False, True, False, False, False],
[False, True, True, True, True, True, False],
[False, True, True, True, True, True, False],
[ True, True, True, True, True, True, True],
[False, True, True, True, True, True, False],
[False, True, True, True, True, True, False],
[False, False, False, True, False, False, False]], dtype=bool)
Теперь я хочу иметь возможность применить эту маску к моему массиву, используя любой элемент в качестве центральной точки. Так, например, с центральной точкой в (1,1) я хочу получить массив вроде:
>>> new_arr
array([[ True, True, True, True, 1., 1., 1., 1.],
[ True, True, True, True, True, 1., 1., 1.],
[ True, True, True, True, 1., 1., 1., 1.],
[ True, True, True, True, 1., 1., 1., 1.],
[ 1., True, 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.]])
Есть ли простой способ применить эту маску?
Редактировать: я не должен был смешивать логические значения и числа с плавающей запятой - это вводило в заблуждение.
>>> new_arr
array([[ 255., 255., 255., 255., 1., 1., 1., 1.],
[ 255., 255., 255., 255., 255., 1., 1., 1.],
[ 255., 255., 255., 255., 1., 1., 1., 1.],
[ 255., 255., 255., 255., 1., 1., 1., 1.],
[ 1., 255., 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.]])
Это больше результат, который мне нужен.
array[mask] = 255
замаскирует массив, используя центральную точку (0 + радиус, 0 + радиус).
Однако я хотел бы иметь возможность разместить маску любого размера в любой точке (y, x) и автоматически обрезать ее до нужного размера.
Я бы сделал это так, где (a, b) - центр вашей маски:
import numpy as np
a, b = 1, 1
n = 7
r = 3
y,x = np.ogrid[-a:n-a, -b:n-b]
mask = x*x + y*y <= r*r
array = np.ones((n, n))
array[mask] = 255
Я просто хотел поделиться со всеми немного более продвинутым применением этой техники, с которой мне просто пришлось столкнуться.
Моя проблема заключалась в том, чтобы применить это круговое ядро для вычисления среднего значения всех значений, окружающих каждую точку в 2D-матрице. Сгенерированное ядро может быть передано в scipy generic filter следующим образом:
import numpy as np
from scipy.ndimage.filters import generic_filter as gf
kernel = np.zeros((2*radius+1, 2*radius+1))
y,x = np.ogrid[-radius:radius+1, -radius:radius+1]
mask = x**2 + y**2 <= radius**2
kernel[mask] = 1
circular_mean = gf(data, np.mean, footprint=kernel)
Надеюсь, это поможет!
Вы можете использовать функцию scipy convolve, которая позволяет вам помещать любую конкретную маску, например ядро, на любое количество заданных координат в вашем массиве:
import numpy as np
from scipy.ndimage.filters import convolve
Сначала создайте массив координат с координатой где вы хотите, чтобы маска (ядро) была центрирована, отмеченная как 2
background = np.ones((10,10))
background[5,5] = 2
print(background)
[[ 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. 2. 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.]]
Создайте свою маску:
y,x = np.ogrid[-3: 3+1, -3: 3+1]
mask = x**2+y**2 <= 3**2
mask = 254*mask.astype(float)
print(mask)
[[ 0. 0. 0. 254. 0. 0. 0.]
[ 0. 254. 254. 254. 254. 254. 0.]
[ 0. 254. 254. 254. 254. 254. 0.]
[ 254. 254. 254. 254. 254. 254. 254.]
[ 0. 254. 254. 254. 254. 254. 0.]
[ 0. 254. 254. 254. 254. 254. 0.]
[ 0. 0. 0. 254. 0. 0. 0.]]
Соедините два изображения:
b = convolve(background, mask)-sum(sum(mask))+1
print(b)
[[ 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. 255. 1. 1. 1. 1.]
[ 1. 1. 1. 255. 255. 255. 255. 255. 1. 1.]
[ 1. 1. 1. 255. 255. 255. 255. 255. 1. 1.]
[ 1. 1. 255. 255. 255. 255. 255. 255. 255. 1.]
[ 1. 1. 1. 255. 255. 255. 255. 255. 1. 1.]
[ 1. 1. 1. 255. 255. 255. 255. 255. 1. 1.]
[ 1. 1. 1. 1. 1. 255. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]
Обратите внимание, что записи функции convolve не коммутируют, т.е. свертка (a, b)!= convolve (b, a)
Обратите внимание также, что если ваша точка находится рядом с ребром, алго не воспроизводит ядро в координате. Чтобы обойти это, вы можете наложить фон на самую большую ось вашего ядра, применить свертку, а затем удалить прокладку.
Теперь вы можете сопоставить любое ядро с любым числом точек в массиве, но обратите внимание, что если два ядра перекрываются, они добавляются при перекрытии. Вы можете установить порог, если вам нужно.
Чтобы сделать его одной удобной функцией:
def cmask(index,radius,array):
a,b = index
nx,ny = array.shape
y,x = np.ogrid[-a:nx-a,-b:ny-b]
mask = x*x + y*y <= radius*radius
return(sum(array[mask]))
Возвращает сумму пикселя в радиусе или возвращает (array [mask] = 2) для любой необходимости.
Вы пытались сделать маску или нули и единицы, а затем использовать умножение массива на элемент? Это канонический путь, более или менее.
Кроме того, вы уверены, что хотите иметь комбинацию чисел и булевых элементов в массиве numpy? NumPy, как следует из названия, лучше всего работает с числами.
Чтобы получить тот же результат, что и в вашем примере, вы можете сделать что-то вроде этого:
>>> new_arr = np.array(ones, dtype=object)
>>> new_arr[mask[2:, 2:]] = True
>>> print new_arr
array([[True, True, True, True, 1.0, 1.0, 1.0, 1.0],
[True, True, True, True, True, 1.0, 1.0, 1.0],
[True, True, True, True, 1.0, 1.0, 1.0, 1.0],
[True, True, True, True, 1.0, 1.0, 1.0, 1.0],
[1.0, True, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]], dtype=object)