索引 numpy 数组的重叠区域

问题描述 投票:0回答:2

我有一个由零组成的二维数组(称为标签)及其坐标列表(称为中心)。对于每个中心,我想在标签数组内围绕它的 5x5 簇中放置一个渐进数字。

如果两个中心非常接近,以至于相应的簇重叠,那么我希望标签数组优先考虑较低的标签值。换句话说,如果簇 2 与簇 1 重叠,那么我希望簇 1 为 5x5,簇 2 更小。

我已成功将此过程编码如下:

import numpy as np

labels = np.zeros((10,20))

centers = [(4,4), (7,7), (5,10), (5,17)]


for i, center in enumerate(centers, start=1):
    # find the coordinates for the 5x5 cluster centered in center.
    cluster = np.ix_(np.arange(center[0]-2, center[0]+3,1),
                     np.arange(center[1]-2, center[1]+3,1))
    
    # create a temporary label array with all zeros
    temp_label = np.zeros_like(labels)
    
    # set the label value in the temporary array in the position corresponding to the cluster 
    temp_label[cluster] = i
    
    # apply some boolean algebra
    # (labels == 0) is a bool array corresponding to all positions that are not yet belonging to a label
    # (labels == 0) * temp_label is like the temp_label, but only where the labels array is still free
    # adding the labels back is ensuring that all previous labels are also counted. 
    labels = (labels == 0) * temp_label + labels


print(labels)

输出:

[[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. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 1. 1. 1. 1. 0. 3. 3. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 1. 1. 1. 1. 1. 0. 3. 3. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 1. 1. 1. 1. 1. 2. 2. 2. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 1. 1. 1. 1. 1. 2. 2. 2. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 0. 0. 0. 2. 2. 2. 2. 2. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 0. 0. 0. 2. 2. 2. 2. 2. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 2. 2. 2. 2. 2. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]

这个片段实际上正在做我想做的事情。簇 1 和 4 是完整的,而相互接触的簇 2 和 3 仅是部分的。为了实现这一点,我每次都必须传递一个临时数组。

更好的解决方案是什么?

python arrays numpy indexing numpy-ndarray
2个回答
0
投票

您可以以相反的顺序编写补丁,以避免复杂(更昂贵)的基于掩码的计算。

使用 Numpy 编写非常小的补丁总是很昂贵,尽管肯定有更快的纯 Numpy 解决方案(也可能是复杂的解决方案)。这是因为 Numpy 针对计算大型数组进行了优化,并且由于昂贵的相对较大的临时数组(使代码更加受内存限制),任何向量化操作显然都不是最佳的。这个问题的关键就是使用基于编译的模块,如 Numba 或 Cython

这是 Numba 中混合两种解决方案的解决方案:

import numpy as np
import numba as nb

def compute_naive(centers):
    labels = np.zeros((10,20))

    for i, center in enumerate(centers, start=1):
        cluster = np.ix_(np.arange(center[0]-2, center[0]+3,1), 
                         np.arange(center[1]-2, center[1]+3,1))
        temp_label = np.zeros_like(labels)
        temp_label[cluster] = i
        labels = (labels == 0) * temp_label + labels

    return labels

@nb.njit('(int32[:,::1],)')
def compute_numba(centers):
    labels = np.zeros((10,20))

    for i, center in enumerate(centers[::-1]):
        cy, cx = center
        yStart, yEnd = max(cy-2, 0), min(cy+3, labels.shape[0])
        xStart, xEnd = max(cx-2, 0), min(cx+3, labels.shape[1])
        for y in range(yStart, yEnd):
            for x in range(xStart, xEnd):
                labels[y, x] = centers.shape[0] - i

    return labels

centers = [(4,4), (7,7), (5,10), (5,17)]
npCenters = np.array(centers, dtype=np.int32)
assert np.allclose(compute_naive(centers), compute_numba(npCenters))
%timeit -n 1000 labels = compute_numba(npCenters)

Numba 解决方案比这个非常小的示例中的初始代码快 >100 倍。它应该在更大规模的用例上更快


0
投票
我认为你肯定可以使用一些诡计......

    也许您可以以相反的顺序迭代中心,并简单地覆盖任何以前的标签,而不是计算“未设置”标签的掩码。
  • 您也许可以使用滑动窗口视图来避免构建
  • np.ix_
    网格。
设置:

import numpy as np from numpy.lib.stride_tricks import sliding_window_view as swv labels = np.zeros((10,20)) centers = [(4,4), (7,7), (5,10), (5,17)] H, W = 5, 5
解决方案:

view = swv(labels, (H, W), writeable=True) for lbl, (r, c) in reversed(list(enumerate(centers, start=1))): view[r - H//2, c - W//2] = lbl


如果你好奇的话,还有更多避免循环的技巧......

虽然以下内容对我有用......但它可能是非法的,因为我们依赖于

view[...] = ...

的书写顺序,我不确定这是否一致。

rows, cols = np.transpose(centers[::-1]) values = np.arange(len(centers), 0, -1) view[rows - H//2, cols - W//2] = values[:, None, None]
>>> print(labels)
[[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. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 1. 1. 1. 1. 0. 3. 3. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 1. 1. 1. 1. 1. 0. 3. 3. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 1. 1. 1. 1. 1. 2. 2. 2. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 1. 1. 1. 1. 1. 2. 2. 2. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 0. 0. 0. 2. 2. 2. 2. 2. 3. 3. 3. 0. 0. 4. 4. 4. 4. 4.]
 [0. 0. 0. 0. 0. 2. 2. 2. 2. 2. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 2. 2. 2. 2. 2. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
    
© www.soinside.com 2019 - 2024. All rights reserved.