[[  0,   0,   0,   0, 255,   0,   0,   0,   0],
       [  0,   0, 255, 255, 255, 255, 255,   0,   0],
       [  0, 255, 255, 255, 255, 255, 255, 255,   0],
       [  0, 255, 255, 255, 255, 255, 255, 255,   0],
       [255, 255, 255, 255, 255, 255, 255, 255, 255],
       [  0, 255, 255, 255, 255, 255, 255, 255,   0],
       [  0, 255, 255, 255, 255, 255, 255, 255,   0],
       [  0,   0, 255, 255, 255, 255, 255,   0,   0],
       [  0,   0,   0,   0, 255,   0,   0,   0,   0]]

我有一个像上面那样的掩码array.我想得到属于掩模周长的x和y坐标.周长点如下图所示:

  [[  0,   0,   0,   0, 255,   0,   0,   0,   0],
   [  0,   0, 255, 255,   0, 255, 255,   0,   0],
   [  0, 255,   0,   0,   0,   0,   0, 255,   0],
   [  0, 255,   0,   0,   0,   0,   0, 255,   0],
   [255,   0,   0,   0,   0,   0,   0,   0, 255],
   [  0, 255,   0,   0,   0,   0,   0, 255,   0],
   [  0, 255,   0,   0,   0,   0,   0, 255,   0],
   [  0,   0, 255, 255,   0, 255, 255,   0,   0],
   [  0,   0,   0,   0, 255,   0,   0,   0,   0]]

在上面的数组中,我可以只使用numpy.nonzero(),但我无法将此逻辑应用于原始数组,因为它返回一个数组元组,每个数组包含所有非零元素的所有x或y值,而不按行划分.

我写了下面的代码,虽然有效,但效率似乎很低:

height = mask.shape[0]
width = mask.shape[1]

y_coords = []
x_coords = []
for y in range(1,height-1,1):
           for x in range(0,width-1,1):
               val = mask[y,x]
               prev_val = mask[y,(x-1)]
               next_val = mask[y, (x+1)]
               top_val = mask[y-1, x]
               bot_val = mask[y+1, x]
               if (val != 0 and prev_val == 0) or (val != 0 and next_val == 0) or (val != 0 and top_val == 0) or (val != 0 and bot_val == 0):
                   y_coords.append(y)
                   x_coords.append(x)

我是python新手,希望学习更好的方法.也许用Numpy?

推荐答案

我研究了一下你的问题,找到了一个解决方案,我意识到你可以使用卷积来计算每个单元格的相邻255个数,然后根据适当的相邻值对点进行过滤.

我在下面给出了详细的解释,尽管其中一部分是反复试验,如果您了解卷积可以计算二进制图像中的邻居,您可以跳过它直接进入代码.


First observation: When does a point belong to the perimeter of the mask?
Well, that point has to have a value of 255 and "around" it, there must be at least one (and possibly more) 0.

Next: What is the definition of "around"?
We could consider all four cardinal (i.e. North, East, South, West) neighbors. In this case, a point of the perimeter must have at least one cardinal neighbor which is 0.
You have already done that, and truly, I cannot thing of a faster way by this definition.

What if we extended the definition of "around"?
Now, let's consider the neighbors of a point at (i,j) all points along an N x N square centered on (i,j). I.e. all points (x,y) such that i-N/2 <= x <= i+N/2 and j-N/2 <= y <= j+N/2 (where N is odd and ignoring out of bounds for the moment).
This is more useful from a performance point of view, because the operation of sliding "windows" along the points of 2D arrays is called a "convolution" operation. There are built in functions to perform such operations on numpy arrays really fast. The scipy.ndimage.convolve works great.
I won't attempt to fully explain convolutions here (the internet is ful of nice visuals), but the main idea is that the convolution essentially replaces the value of each cell with the weighted sum of the values of all its neighboring cells. Depending on what weight matrix, (or kernel) you specify, the convolution does different things.

现在,如果你的掩码是1和0,为了计算一个单元格周围相邻掩码的数量,你需要一个到处都是1的核矩阵(因为加权和将简单地将掩码的原始掩码相加,并取消0).我们将把数值从[0255]zoom 到[0,1].

很好,我们知道如何快速计算一个区域内某个点的邻域,但有两个问题是

  1. 我们应该 Select 什么面积?
  2. 既然我们已经包括对角线和更遥远的邻居,那么周长中的点有多少个邻居?

我想有一个明确的答案,但我做了一些try 和错误.结果表明,我们需要N=5个,在这种情况下,原始掩码中每个点的邻域数为1,如下所示:

[[ 3  5  8 10 11 10  8  5  3]
 [ 5  8 12 15 16 15 12  8  5]
 [ 8 12 17 20 21 20 17 12  8]
 [10 15 20 24 25 24 20 15 10]
 [11 16 21 25 25 25 21 16 11]
 [10 15 20 24 25 24 20 15 10]
 [ 8 12 17 20 21 20 17 12  8]
 [ 5  8 12 15 16 15 12  8  5]
 [ 3  5  8 10 11 10  8  5  3]]

将该矩阵与原始掩码进行比较,周长上的点是值介于1115(包括1115)之间的点[1].因此,我们只需使用np.where()过滤掉其余部分.

最后一个警告:我们需要明确地告诉convolve函数如何处理边缘附近的点,在那里N x N窗口不适合.在这些情况下,我们告诉它将越界值视为0.

完整代码如下:

from scipy import ndimage as ndi

mask   //= 255
kernel = np.ones((5,5))
C      = ndi.convolve(mask, kernel, mode='constant', cval=0)

#print(C) # The C matrix contains the number of neighbors for each cell.

outer  = np.where( (C>=11) & (C<=15 ), 255, 0)
print(outer)



[[  0   0   0   0 255   0   0   0   0]
 [  0   0 255 255   0 255 255   0   0]
 [  0 255   0   0   0   0   0 255   0]
 [  0 255   0   0   0   0   0 255   0]
 [255   0   0   0   0   0   0   0 255]
 [  0 255   0   0   0   0   0 255   0]
 [  0 255   0   0   0   0   0 255   0]
 [  0   0 255 255   0 255 255   0   0]
 [  0   0   0   0 255   0   0   0   0]]

[1] 注意,我们还将点本身作为其自己的邻居之一计算.没关系.

Python相关问答推荐

从源代码显示不同的输出(机器学习)(Python)

如何使用Azure Function将xlsb转换为xlsx?

解决Geopandas和Altair中的正图和投影问题

删除Dataframe中的第一个空白行并重新索引列

在round函数中使用列值

从列表中分离数据的最佳方式

如何从一个维基页面中抓取和存储多个表格?

使用Scikit的ValueError-了解

PYODBC错误(SQL包含-26272个参数标记,但提供了235872个参数,HY 000)

在Python中使用unittest中的补丁进行动态模拟

通过PyTorch中的MIN函数传递渐变

从pandas框架中删除重复的子框架

获取给出特定产品的所有可能组合的数量

有没有更python的方法来复制python中列表的第n个元素?例如,使用列表理解

用Gekko拟合两个总体的测量值

将共同的交付成果分解为单独的变量

如何分解在某些行中为空,但在其他行中填充的pandas框架

在Python中使用xpath和selenium Select HTML元素

不理解它怎么会是索引错误:列出索引超出范围

如何对 torch 张量中的数据进行切片?