过滤二维数组并从中间返回坐标 [英] Filter 2D array and return co-ordinates from intermediate
问题描述
我有一个二维零数组,在 (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 的那些的坐标.>
我从图像分析中了解到,通过内核对 2D 数组进行卷积很容易,但不会产生中间结果.在上面的二维数组中,它会返回 (1,8) 和 (3,7).
是否有一些包函数可以使这个过程简单易行,还是我必须自己实现?一如既往,感谢所有帮助
这是它的一个 numpy 实现.您可以通过修改它来提高性能.
这里,num_ones
是你想过滤的内核中1的下限和上限,指的是当这个内核中的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.]])内核 = np.array([[1.,0.,1.],\[0.,1.,0.],\[0.,1.,0.]])sub_shape = kernel.shape#具有非零值的内核数的阈值num_ones = [2,3]#将矩阵划分为内核大小的子矩阵view_shape = tuple(np.subtract(a.shape, sub_shape) + 1) + sub_shape步幅 = a.strides + a.stridessub_matrices = np.lib.stride_tricks.as_strided(a,view_shape,strides)#将非零元素转换为 1(虚拟表示)sub_matrices[sub_matrices>0.] = 1.#做卷积m = np.einsum('ij,klij->kl',kernel,sub_matrices)#找到满足非零元素条件的子矩阵filt = np.argwhere(np.logical_and(m>=num_ones[0], m<=num_ones[1]))#对于每个sub_matix,找到位于内核非零元素中的零元素输出 = []对于过滤中的 [i,j]:output.append(np.argwhere((sub_matrices[i,j,:,:]==0)*kernel) + [i, j])
输出是一个索引数组数组,其中每个数组都是索引,其中每个内核应用程序在图像的每个位置 [i,j]
中满足您的条件.如果您希望将它们全部聚合,您可以堆叠所有数组并获取它的唯一列表.我不确定在多次出现的情况下您希望输出如何.
输出:
输出 =[[1 8][3 7]]
更新:关于 einsum:
我会推荐这篇关于 einsum 的帖子来学习:了解 NumPy 的 einsum
sub_matrices
是一个 4 维数组.sub_matrices[k,l,:,:]
是 a
从位置 [k,l]
开始的子矩阵和核的形状.(后来为了我们的目的,我们将它的所有非零值更改为 1)
m = np.einsum('ij,klij->kl',kernel,sub_matrices)
两个维度相乘 i
和 j
kernel
到 sub_matrices
数组的最后两个维度 i
和 j
(换句话说,它按元素相乘核到子矩阵 sub_matrices[k,l,:,:]
) 并将所有元素相加到 m[k,l]
.这被称为 kernel
到 a
的二维卷积.
I have a 2D array of zeros with some positive integers at (1,6) and (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.]]
And I want to filter the array by a custom kernel:
[[1 0 1]
[0 1 0]
[0 1 0]]
I want to filter the array with this kernel and when 2 or 3 of the ones in this kernel are multiplied by a positive integer, I want it to return the co-ordinates of the ones that were multiplied by 0.
I know from image analysis that it's easy to convolve a 2D array by a kernel but it doesn't yield the intermediate results. On the above 2D array, it would return (1,8) and (3,7).
Is there some package functions that I can use to make this process simple and easy, or will I have to implement it myself? As always, all help is appreciated
This is a numpy implementation of it to start with. You can increase performance probably by modifying it.
Here, num_ones
is the lower and upper number of ones in the kernel you would like to filter, referring to when 2 or 3 of the ones in this kernel are multiplied by a positive integer
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 is an array of indices arrays where each array is indices where your condition is met per kernel application in each location [i,j]
of your image. If you wish to aggregate them all, you can stack all arrays and take a unique list of it. I am not sure how you would like the output be in case of multiple occurrences.
output:
output =
[[1 8]
[3 7]]
UPDATE: regarding einsum:
I would recommend this post about einsum to learn: Understanding NumPy's einsum
sub_matrices
is a 4-dimensional array. sub_matrices[k,l,:,:]
is sub matrix of a
starting at position [k,l]
and shape of kernel. (later we changed all non-zero values of it to 1 for our purpose)
m = np.einsum('ij,klij->kl',kernel,sub_matrices)
multiplies two dimensions i
and j
of kernel
into last two dimensions i
and j
of sub_matrices
array (in other words, it element-wise multiplies kernel to sub matrices sub_matrices[k,l,:,:]
) and sums all elements into m[k,l]
. This is known as 2D convolution of kernel
into a
.
这篇关于过滤二维数组并从中间返回坐标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!