【问题标题】:Efficiently apply function to spheric neighbourhood in numpy array有效地将函数应用于 numpy 数组中的球形邻域
【发布时间】:2019-05-06 03:54:21
【问题描述】:

我在 Python 中有一个 3D numpy 浮点值数组。 我需要检索半径为 r 的球体中的所有元素 一个中心点 P(x, y, z)。然后,我想将一个函数应用于球体点 更新它们的值并需要到中心点的距离来执行此操作。我做了很多次这些步骤 大半径值,所以我想有一个同样有效的解决方案 尽可能。

我当前的解决方案只检查球体边界框中的点, 如此处所示:Using a QuadTree to get all points within a bounding circle。 代码草图如下所示:

# P(x, y, z): center of the sphere
for k1 in range(x - r, x + r + 1):
    for k2 in range(y - r, y + r + 1):
        for k3 in range(z - r, z + r + 1):
            # Sphere center - current point distance
            dist = np.sum((np.array([k1, k2, k3]) - np.array([x, y, z])) ** 2)

            if (dist <= r * r):
                # computeUpdatedValue(distance, radius): function that computes the new value of the matrix in the current point 
                newValue = computeUpdatedValue(dist, r)

                # Update the matrix
                mat[k1, k2, k3] = newValue

但是,我认为应用蒙版来检索点,然后, 基于距离以矢量化方式更新它们更有效。 我已经看到如何应用循环内核 (How to apply a disc shaped mask to a numpy array?), 但我不知道如何在每个掩码元素上有效地应用函数(取决于索引)。

【问题讨论】:

    标签: python numpy vectorization mask


    【解决方案1】:

    编辑:如果您的数组与您正在更新的区域相比非常大,那么下面的解决方案将占用比必要更多的内存。您可以将相同的想法应用于球体可能下落的区域:

    def updateSphereBetter(mat, center, radius):
        # Find beginning and end of region of interest
        center = np.asarray(center)
        start = np.minimum(np.maximum(center - radius, 0), mat.shape)
        end = np.minimum(np.maximum(center + radius + 1, 0), mat.shape)
        # Slice region of interest
        mat_sub = mat[tuple(slice(s, e) for s, e in zip(start, end))]
        # Center coordinates relative to the region of interest
        center_rel = center - start
        # Same as before but with mat_sub and center_rel
        ind = np.indices(mat_sub.shape)
        ind = np.moveaxis(ind, 0, -1)
        dist_squared = np.sum(np.square(ind - center_rel), axis=-1)
        mask = dist_squared <= radius * radius
        mat_sub[mask] = computeUpdatedValue(dist_squared[mask], radius)
    

    请注意,由于mat_submat 的视图,因此更新它会更新原始数组,因此这会产生与以前相同的结果,但资源更少。


    这是一个小概念证明。我定义了computeUpdatedValue 以便它显示与中心的距离,然后绘制了示例的几个“部分”:

    import numpy as np
    import matplotlib.pyplot as plt
    
    def updateSphere(mat, center, radius):
        # Make array of all index coordinates
        ind = np.indices(mat.shape)
        # Compute the squared distances to each point
        ind = np.moveaxis(ind, 0, -1)
        dist_squared = np.sum(np.square(ind - center), axis=-1)
        # Make a mask for squared distances within squared radius
        mask = dist_squared <= radius * radius
        # Update masked values
        mat[mask] = computeUpdatedValue(dist_squared[mask], radius)
    
    def computeUpdatedValue(dist_squared, radius):
        # 1 at the center of the sphere and 0 at the surface
        return np.clip(1 - np.sqrt(dist_squared) / radius, 0, 1)
    
    mat = np.zeros((100, 60, 80))
    updateSphere(mat, [50, 20, 40], 20)
    
    plt.subplot(131)
    plt.imshow(mat[:, :, 30], vmin=0, vmax=1)
    plt.subplot(132)
    plt.imshow(mat[:, :, 40], vmin=0, vmax=1)
    plt.subplot(133)
    plt.imshow(mat[:, :, 55], vmin=0, vmax=1)
    

    输出:

    【讨论】:

      猜你喜欢
      • 2017-01-11
      • 1970-01-01
      • 2019-07-25
      • 2020-12-17
      • 1970-01-01
      • 1970-01-01
      • 2014-04-20
      • 2018-01-24
      • 2020-02-24
      相关资源
      最近更新 更多