Python:检查点是否在球体中

时间:2017-03-24 13:29:25

标签: python arrays numpy

我有以下问题。我有一个三维坐标的数据集,每个坐标都是一个细胞/球体的中心。现在我必须检查三维网格中的点(均为零值)是否是该球体的邻域,如果是,则得到值+1。 trhee尺寸网格具有距坐标最大x,y,z的尺寸。我的第一个想法是使用vtk为坐标列表中的python创建球体对象。此外,我创建了一个三维零的numpy数组。现在我可以检查网格中的每个点是否在球体内部,如果不是,并且它是球体的邻居,它将获得+1。

如果在带有for循环的中心(x,y,z)的球体中,检查网格的所有坐标将太昂贵(N ^ 3)。有没有一种简单的方法可以从3D网格中的球体获取邻居坐标,或检查它们是否在球体中是否在球体内?

我看到matplotlib有函数" contains_points"。在另一个主题中有一个例子:

>>> from matplotlib import path
>>> p = path.Path([(0,0), (0, 1), (1, 1), (1, 0)])  # square with legs     length 1 and bottom left corner at the origin
>>> p.contains_points([(.5, .5)])
array([ True], dtype=bool)

当然,我们也可以使用一系列积分:

>>> points = np.array([.5, .5]).reshape(1, 2)
>>> points
array([[ 0.5,  0.5]])
>>> p.contains_points(points)
array([ True], dtype=bool)

是否可以针对3个维度执行此操作,或者是否可以执行此操作?

2 个答案:

答案 0 :(得分:1)

假设我正确地理解了你的问题,我建议简单地迭代你的球体并确定半径内的整数坐标。最简单的方法(不一定是最好的方法)是在边界框内找到坐标,然后按欧几里德距离进行过滤。如果坐标空间非常大,稀疏矩阵将有助于减少内存使用量。

import numpy as np
import math
import itertools

spheres = np.random.rand(10,3) * 100 #ten random points in 3-space from 0 - 100
radius = 2 #spheres have radius 2

sparse = {} #use a dictionary with tuple keys as a sparse 3d matrix

for sphere in spheres:
    #outer bounding box
    x0 = math.floor(sphere[0]-radius)
    x1 = math.ceil(sphere[0]+radius)
    y0 = math.floor(sphere[1]-radius)
    y1 = math.ceil(sphere[1]+radius)
    z0 = math.floor(sphere[2]-radius)
    z1 = math.ceil(sphere[2]+radius)
    #add 1 to upper bounds to range is inclusive
    for coords in itertools.product(range(x0,x1+1), range(y0,y1+1), range(z0,z1+1)):
        if radius**2 >= sum((sphere - coords)**2): #euclidean distance is smaller than radius
            value = sparse.get(coords, 0) + 1
            sparse[coords] = value

根据3d网格的大小和球体的半径,通过仅考虑网格上对齐的方形边界框,可以改善计算每个球体中每个点的距离。随着半径的增加,相对于计算出的距离最终落在每个球体之外,这将大约达到50%的效率。

编辑:

根据您的意见,我已经改变了我的方法......

想要找到球体周围的所有点而不是球体中的所有点导致我采用略微不同的方法。第一部分实际上是相同的,但不是将结果直接写入稀疏数组,而是使用区域的密集数组。然后我们可以使用卷积来找到填充区域的边缘(谷歌"边缘滤波器卷积"更多阅读)。可以更改此过滤器以包括或排除对角线,但在此示例中,我已将它们包括在内。从技术上讲,算法复杂度更高,因为卷积是ak维数组的O(n k )复杂度(在本例中为O(n 3 )),但是scipy实现了这个功能在编译的c而不是纯python中有效。最后,我们遍历我们找到边缘的区域并将它们添加到稀疏数组中。

import numpy as np
import math
from scipy.ndimage.filters import convolve

spheres = np.random.rand(8,3) * 10 #ten random points in 3-space from 0 - 100
radius = 3 #spheres have radius 2

sparse = {} #use a dictionary with tuple keys as a sparse 3d matrix

kernel = np.ones([3,3,3]) #ones will multiply with non-zero elements of spherical region
kernel[1,1,1] = -30 #value will be pulled negative if spherical region intersects center "pixel"
for sphere in spheres:
    x0 = math.floor(sphere[0]-radius)
    x1 = math.ceil(sphere[0]+radius)
    y0 = math.floor(sphere[1]-radius)
    y1 = math.ceil(sphere[1]+radius)
    z0 = math.floor(sphere[2]-radius)
    z1 = math.ceil(sphere[2]+radius)
    region = np.zeros([x1-x0+1, y1-y0+1, z1-z0+1])
    for index, x in np.ndenumerate(region):
        #align new axes
        coords = np.array([x0, y0, z0]) + index
        if radius**2 >= sum((sphere - coords)**2): #euclidean distance is smaller than radius
            region[index] = 1
    edge = convolve(region, kernel, mode='constant', cval=0.0) > 0 #convolve and test if greater than 0
    for index, x in np.ndenumerate(edge):
        if edge:
            value = sparse.get((index[0]+x0, index[1]+y0, index[2]+z0), 0)
            sparse[(index[0]+x0, index[1]+y0, index[2]+z0)] = value + 1

答案 1 :(得分:0)

为什么不计算给定点的径向距离是否<=球体“最后”点之一的径向距离?如果为True,则包含它。这是O(n)