Здесь предлагается один векторизованный подход. Шаги:
Получите скользящие 2D-окна размером с ядро, ведущие к 4D-массиву. Мы можем использовать skimage's view_as_windows
, чтобы получить их как представление и, таким образом, избежать создания дополнительной памяти для этого.
Выберите окна, центрированные по нулям, путем индексации в массиве 4D. Это вызывает копию. Но если предположить, что количество нулей относительно меньше, чем общее количество элементов во входном массиве, все должно быть в порядке.
Для каждого из этих выбранных окон сместите каждое окно с правильным смещением с идеей использования np.bincount
для выполнения подсчета. Таким образом, используйте bincount
и получите максимальное количество, исключая нули. argmax для максимального количества должен быть нашим парнем!
Вот реализация, охватывающая эти шаги -
from skimage.util import view_as_windows as viewW
def fill_zero_regions(a, kernel_size=3):
hk = kernel_size//2 # half_kernel_size
a4D = viewW(a, (kernel_size,kernel_size))
sliced_a = a[hk:-hk,hk:-hk]
zeros_mask = sliced_a==0
zero_neighs = a4D[zeros_mask].reshape(-1,kernel_size**2)
n = len(zero_neighs) # num_zeros
scale = zero_neighs.max()+1
zno = zero_neighs + scale*np.arange(n)[:,None] # zero_neighs_offsetted
count = np.bincount(zno.ravel(), minlength=n*scale).reshape(n,-1)
modevals = count[:,1:].argmax(1)+1
sliced_a[zeros_mask] = modevals
return a
Пробный запуск -
In [23]: a
Out[23]:
array([[9, 9, 9, 0, 0, 0, 0, 1, 1, 1],
[9, 9, 9, 9, 0, 7, 1, 1, 1, 1],
[9, 9, 9, 9, 0, 2, 2, 1, 1, 1],
[9, 9, 9, 8, 0, 2, 2, 1, 1, 1],
[9, 9, 9, 8, 0, 2, 2, 2, 1, 1],
[4, 4, 4, 4, 0, 2, 2, 2, 1, 1],
[4, 6, 6, 4, 0, 0, 0, 0, 0, 0],
[4, 6, 6, 4, 0, 0, 0, 0, 0, 0],
[4, 4, 4, 4, 5, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 5, 5, 5, 5, 5, 5]])
In [24]: fill_zero_regions(a)
Out[24]:
array([[9, 9, 9, 0, 0, 0, 0, 1, 1, 1],
[9, 9, 9, 9, 9, 7, 1, 1, 1, 1],
[9, 9, 9, 9, 2, 2, 2, 1, 1, 1],
[9, 9, 9, 8, 2, 2, 2, 1, 1, 1],
[9, 9, 9, 8, 2, 2, 2, 2, 1, 1],
[4, 4, 4, 4, 2, 2, 2, 2, 1, 1],
[4, 6, 6, 4, 4, 2, 2, 2, 1, 0],
[4, 6, 6, 4, 4, 5, 5, 5, 5, 0],
[4, 4, 4, 4, 5, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 5, 5, 5, 5, 5, 5]])
Как видно, мы не решаем граничные случаи. Если необходимо, используйте массив с нулевым дополнением в качестве входного массива, что-то вроде этого: np.pad(a, (k//2,k//2), 'constant')
, с k
в качестве размера ядра (=3
для примера).
person
Divakar
schedule
09.09.2017