【问题标题】:Python point lookup (coordinate binning?)Python点查找(坐标分箱?)
【发布时间】:2011-02-23 15:16:26
【问题描述】:

您好,

我正在尝试将点数组 (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 例程?

谢谢!

【问题讨论】:

  • 一位回答者认为您想“计算密度”;一位回答者认为您想让代码运行得更快;一位回答者(我)认为你想让你的代码更清晰......也许你应该澄清你的问题:)
  • 无需澄清 - 我从不同方面得到了很好的答案。更多脑食:)

标签: python geometry numpy


【解决方案1】:

如果我正确理解了您的问题,那么假设您的点也是 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

【讨论】:

    【解决方案2】:

    这些框轴对齐了吗?即边缘是否平行于坐标轴?如果是这样,这可以通过 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]
    

    修改 >= 和

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

    【讨论】:

    • X[:,1] 语法是什么?我遇到了非常奇怪的错误。
    • 这些需要是 NumPy 数组,其大小按照我指定的方式进行。 X[:,1] 选择第二列中的所有元素。
    【解决方案3】:

    无需太多更改,您的代码可以压缩为:

    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
    

    【讨论】:

      【解决方案4】:

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

      与往常一样,首先说明您是否真的需要这种优化。

      【讨论】:

      • 如果有循环我看不到...四个检查是O(4) = O(1)
      【解决方案5】:

      我使用类似的例程来绘制颜色映射密度图:

      #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 样本,而不是计算密度。

      【讨论】:

        【解决方案6】:

        如果你真的需要使用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)
        

        【讨论】:

          【解决方案7】:

          您确定需要这样复杂的检查吗?

          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
          

          【讨论】:

          • 我希望我误解了你想要达到的目的 :) 戴复杂手套的方法。
          【解决方案8】:

          假设你的盒子是矩形的,不重叠,也没有间隙,那你为什么不直接打电话给numpy.histogram2d呢?见the numpy docs

          【讨论】:

            猜你喜欢
            • 2012-10-14
            • 2020-10-05
            • 1970-01-01
            • 2022-11-28
            • 1970-01-01
            • 2022-12-15
            • 1970-01-01
            • 2021-07-19
            • 1970-01-01
            相关资源
            最近更新 更多