Python点查找(坐标分箱?)

时间:2010-05-25 10:46:12

标签: python geometry numpy

问候,

我正在尝试将点数组(x, y)分成一个方框数[(x0, y0), (x1, y0), (x0, y1), (x1, y1)](元组是角点)

到目前为止,我有以下例程:

def isInside(self, point, x0, x1, y0, y1):
    pr1 = getProduct(point, (x0, y0), (x1, y0))
    if pr1 >= 0:
        pr2 = getProduct(point, (x1, y0), (x1, y1))
        if pr2 >= 0:
            pr3 = getProduct(point, (x1, y1), (x0, y1))
            if pr3 >= 0:
                pr4 = getProduct(point, (x0, y1), (x0, y0))
                if pr4 >= 0:
                    return True
    return False

def getProduct(origin, pointA, pointB):
    product = (pointA[0] - origin[0])*(pointB[1] - origin[1]) - (pointB[0] - origin[0])*(pointA[1] - origin[1])
    return product

有没有更好的方法然后逐点查找?也许一些不明显的numpy常规?

谢谢!

8 个答案:

答案 0 :(得分:2)

如果我正确理解您的问题,那么假设您的积分也是2元组,则以下情况应该有效。

def in_bin(point, lower_corner, upper_corner):
    """
    lower_corner is a 2-tuple - the coords of the lower left hand corner of the
    bin.
    upper_corner is a 2-tuple - the coords of the upper right hand corner of the
    bin.
    """
    return lower_corner <= point <= upper_corner

if __name__ == '__main__':
    p_min = (1, 1) # lower left corner of bin
    p_max = (5, 5) # upper right corner of bin

    p1 = (3, 3) # inside
    p2 = (1, 0) # outside
    p3 = (5, 6) # outside
    p4 = (1, 5) # inside

    points = [p1, p2, p3, p4]

    for p in points:
        print '%s in bin: %s' % (p, in_bin(p, x_min, x_max))

此代码显示您可以直接比较元组 - 文档中有关于此的一些信息:http://docs.python.org/tutorial/datastructures.html#comparing-sequences-and-other-types

答案 1 :(得分:1)

如果没有太多变化,您的代码可以压缩到:

def isInside(self, point, x0, x1, y0, y1):
    return getProduct(point, (x0, y0), (x1, y0)) >= 0 and
           getProduct(point, (x1, y0), (x1, y1)) >= 0 and
           getProduct(point, (x1, y1), (x0, y1)) >= 0 and
           getProduct(point, (x0, y1), (x0, y0)) >= 0

def getProduct(origin, pointA, pointB):
    product = (pointA[0] - origin[0])*(pointB[1] - origin[1]) - (pointB[0] - origin[0])*(pointA[1] - origin[1])
    return product

答案 2 :(得分:1)

您的解决方案是O(N),其中N是点数。如果N足够大并且您运行查询isInside很多次,您可能会考虑对点进行排序,然后使用二进制搜索来查找相关点。

与往常一样,首先要了解您是否真的需要此优化。

答案 3 :(得分:1)

您确定首先需要这么复杂的检查吗?

def isInside(self, point, x0, y0, x1, y1):
  x,y = point
  if x0 > x1: x0,x1 = x1,x0 #these cause no
  if y0 > y1: y0,y1 = y1,y0 #side effect.

  return x0 <= x <= x1 and y0 <= y <= y1

答案 4 :(得分:1)

我使用类似的例程来制作彩色图密度图:

#calculate densities
rho = zeros((nx,ny));
for i in range(N):
    x_sample = int(round(ix[i]))
    y_sample = int(round(iy[i]))

    if (x_sample > 0) and (y_sample > 0) and (x_sample<nx) and (y_sample<ny):
        rho[y_sample,x_sample] = rho[y_sample,x_sample] + 1

您可以存储x和y样本,而不是计算密度。

答案 5 :(得分:1)

如果你真的需要使用getProduct ...打包,拆包和好的变量名称ftw!

def isInside(self, point, x0, x1, y0, y1):
    A = x0,y0
    B = x1,y0
    C = x1,y1
    D = x0,y1

    return getProduct(point, A, B) and
           getProduct(point, B, C) and
           getProduct(point, C, D) and
           getProduct(point, D, A)

def getProduct(origin, pointA, pointB):
    xA,yA = pointA
    xB,yB = pointB
    x,y = point

    return (xA - x)*(yB - y) - (xB - x)*(yB - y)

答案 6 :(得分:1)

这些盒子轴是否对齐?即边缘是否平行于坐标轴?如果是这样,这可以通过NumPy阵列上的矢量化比较非常有效地完成。

def in_box(X, B):
    """
    Takes an Nx2 NumPy array of points and a 4x2 NumPy array of corners that 
    form an axis aligned box.
    """
    xmin = B[:,0].min(); xmax = B[:,0].max()
    ymin = X[:,1].min(); ymax = X[:,1].max()
    return X[X[:,0] > xmin & X[:,0] < xmax & X[:,1] > ymin & X[:,1] < ymax]

修改为&gt; =和&lt; =如果您希望它们具有包容性。

如果你需要任意四边形,matplotlib实际上有一个你可以使用的例程matplotlib.nxutils.points_inside_poly(如果已安装它)或者复制它(它是BSD许可的)。有关所用算法和其他多边形内部测试算法的讨论,请参阅this page

答案 7 :(得分:0)

假设您的盒子是矩形的,不重叠,没有间隙,那你为什么不打电话给numpy.histogram2d?请参阅the numpy docs