Фильтровать 2D массив и вернуть координаты из промежуточного - PullRequest
4 голосов
/ 20 апреля 2020

У меня есть двумерный массив нулей с некоторыми положительными целыми числами в (1,6) и (2,7):

[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 2. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 2. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]

И я хочу отфильтровать массив с помощью собственного ядра:

[[1 0 1]
 [0 1 0]
 [0 1 0]]

Я хочу отфильтровать массив с этим ядром, и когда 2 или 3 из этого ядра умножаются на положительное целое число, я хочу, чтобы он возвращал координаты тех, которые были умножены на 0.

Я знаю из анализа изображений, что ядро ​​легко свернуть двумерный массив, но оно не дает промежуточных результатов. В приведенном выше двумерном массиве он будет возвращать (1,8) и (3,7).

Есть ли какие-нибудь функции пакета, которые я могу использовать, чтобы сделать этот процесс простым и легким, или мне придется реализовать это сам? Как всегда, вся помощь приветствуется

1 Ответ

1 голос
/ 20 апреля 2020

Это numpy реализация этого для начала. Вы можете увеличить производительность, вероятно, изменив ее.

Здесь num_ones - это нижнее и верхнее число единиц в ядре, которое вы хотите отфильтровать, ссылаясь на , когда 2 или 3 из них в этом ядре умножаются на положительное целое число

a = np.array([[0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.],
 [0.,0.,0.,0.,0.,0.,2.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.],
 [0.,0.,0.,0.,0.,0.,0.,2.,0.,0.,0.,0.,0.,0.,0.,0.,0.],
 [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.]])

kernel = np.array([[1.,0.,1.],\
 [0.,1.,0.],\
 [0.,1.,0.]])

sub_shape = kernel.shape
#throshold of number of kernel ones to have non-zero value
num_ones = [2,3]

#divide the matrix into sub_matrices of kernel size
view_shape = tuple(np.subtract(a.shape, sub_shape) + 1) + sub_shape
strides = a.strides + a.strides
sub_matrices = np.lib.stride_tricks.as_strided(a,view_shape,strides)
#convert non_zero elements to 1 (dummy representation)
sub_matrices[sub_matrices>0.] = 1.

#Do convolution
m = np.einsum('ij,klij->kl',kernel,sub_matrices)

#find sub_matrices that satisfy non-zero elements' condition
filt = np.argwhere(np.logical_and(m>=num_ones[0], m<=num_ones[1]))
#for each sub_matix find the zero elements located in non-zero elements of kernel
output = []
for [i,j] in filt:
  output.append(np.argwhere((sub_matrices[i,j,:,:]==0)*kernel) + [i, j])

output - это массив массивов индексов, где каждый массив - это индексы, где выполняется ваше условие для приложения ядра в каждом местоположении [i,j] вашего изображения. Если вы хотите sh объединить их все, вы можете сложить все массивы и получить уникальный список из них. Я не уверен, как бы вы хотели, чтобы выходные данные были в случае нескольких вхождений.

output:

output =
[[1 8]
 [3 7]] 

UPDATE: относительно einsum:

Я бы порекомендовал этот пост о einsum, чтобы узнать: Понимание Einsum NumPy

sub_matrices - это 4-мерный массив. sub_matrices[k,l,:,:] является подматрицей a, начиная с позиции [k,l] и формы ядра. (позже мы изменили все его ненулевые значения на 1 для нашей цели)

m = np.einsum('ij,klij->kl',kernel,sub_matrices) умножает два измерения i и j из kernel на два последних измерения i и j из sub_matrices массива (другими словами, он поэлементно умножает ядро ​​на подматрицы sub_matrices[k,l,:,:]) и суммирует все элементы в m[k,l]. Это известно как 2D свертка kernel в a.

...