这是它的一个 numpy 实现。您可以通过修改它来提高性能。
Here, 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])
输出是索引数组的数组,其中每个数组都是索引,其中每个位置的每个内核应用程序都满足您的条件[i,j]
你的形象。如果您希望将它们全部聚合,您可以堆叠所有数组并获取其唯一列表。我不确定在多次出现的情况下您希望输出如何。
输出:
output =
[[1 8]
[3 7]]
更新:关于 einsum:
我会推荐这篇关于 einsum 的文章来学习:理解 NumPy 的 einsum https://stackoverflow.com/questions/26089893/understanding-numpys-einsum
sub_matrices
是一个4维数组。sub_matrices[k,l,:,:]
是子矩阵a
从位置开始[k,l]
和内核的形状。 (后来出于我们的目的,我们将其所有非零值更改为 1)
m = np.einsum('ij,klij->kl',kernel,sub_matrices)
二维相乘i
and j
of kernel
进入最后两个维度i
and j
of sub_matrices
数组(换句话说,它按元素将内核乘以子矩阵sub_matrices[k,l,:,:]
) 并将所有元素求和为m[k,l]
。这称为 2D 卷积kernel
into a
.