【问题标题】:Calculating the intersection area between two rectangles with axes not aligned计算轴未对齐的两个矩形之间的相交区域
【发布时间】:2018-03-11 20:53:06
【问题描述】:

我想计算两个坐标轴未对齐但坐标轴角度小于 30 度的矩形之间的联合 IoU 交集。也寻求一个近似值。

一种可能的解决方案是检查两个矩形之间的角度是否小于 30 度,然后将它们平行旋转以对齐轴。从这里很容易计算 IoU

另一种可能性是对交叉点使用蒙特卡罗方法(生成一个点,查找该点是否在一个矩形的某条线下方和另一个矩形的某条线上方),但这似乎很昂贵,因为我需要使用此计算很多次。

我希望那里有更好的东西;可能是几何库,也可能是计算机视觉人员的算法。

我正在尝试使用深度神经网络来学习抓取位置。我的算法应该预测 rgb 图像中对象的边界框(矩形)。对于任何图像,我也有基本事实(另一个矩形)边界框。从这两个矩形中,我需要 IoU

有什么想法吗?

【问题讨论】:

    标签: python math machine-learning tensorflow computer-vision


    【解决方案1】:

    This might help

    使用勾股定理怎么样?由于您有两个矩形,当它们相交时,您将有一个或多个三角形,每个三角形都有一个 90° 角。

    由于您还知道两个矩形之间的角度(在我的示例中为 20°)以及每个矩形的坐标,因此您可以使用适当的函数(cos/sin/tan)来知道所有边的长度的三角形。

    希望对你有帮助

    【讨论】:

      【解决方案2】:

      在 O'Rourke 的“Computational Geometry in C”一书中描述了计算两个凸多边形相交的非常有效的算法。

      C 代码可用at the book page (convconv)。

      算法遍历第一个多边形的边缘,检查第二个多边形顶点的方向以检测交叉点。当两个后续顶点位于边的不同侧时,就会发生相交(有很多技巧案例)。算法大纲为here

      【讨论】:

      • 谢谢,但这对我的任务来说有点过分了,而且理解 C 代码和用 python 编写也会造成损失。我总是只有两个矩形。如果您还可以想到任何近似值(在问题中提到的条件下),将不胜感激。
      • 你没有提到——两个矩形是否有相似的方向(旋转角度)。你为什么强调30度——这个角度有什么特别之处?在这种情况下,我无法想象任何估计方法都比精确解决方案更简单。
      • 矩形的方向不同。如果预测的矩形与地面实况矩形(标记的数据图像)的方向大于 30 度,这将不被接受。如果方向小于 30 度,机器人的抓手仍然可以抓住物体。因此,矩形实际上是抓取位置。我想到的一个近似值是:1. 检查矩形的方向是否小于 30 度 2 围绕它们各自中心的轴旋转它们直到面向图像的3轻松计算IoU
      【解决方案3】:

      您可以考虑多种数值方法,实际上是将矩形“渲染”成一些“画布”/画布,并遍历像素以进行统计。画布的大小应该是整个场景的边界框的大小,实际上你可以通过选择每个轴出现的最小和最大坐标来找到。

      1)“最CG”的做法:真正得到一个渲染库,一个矩形渲染红色,另一个矩形透明蓝色。然后访问每个像素,如果它有一个非0的红色分量,它属于第一个矩形,如果它有一个非0的蓝色分量,它属于第二个矩形。如果两者都有,它也属于交叉点。这种方法编码成本低,但即使在渲染阶段也需要写入和读取画布,这比仅写入要慢。这甚至可以在 GPU 上完成,尽管我不确定设置成本和获取结果是否不会影响这样一个简单场景的好处。

      2) 另一种 CG 方法将渲染成 2 个数组,最好是每像素 1 字节的变体,为了速度(您可能需要及时返回一点才能找到这样的专用渲染图书馆)。这样,渲染器只会将每个矩形写入一个数组,并在创建统计信息时从两个数组中读取

      3) 由于写入和读取像素需要时间,您可以做一些捷径,但它需要更多编码:可以通过收集每条扫描线的最小和最大坐标来渲染凸形,并在两者之间进行填充。如果你自己做,你可以省去填充部分以及最后读取和检查每个像素的步骤。为两个矩形建立这样的最小-最大列表,然后你“只需”检查它们的关系/顺序对于每条扫描线,以识别重叠

      然后是数学方法:这并不是真正有用,请参阅下面的编辑,虽然您不太可能找到一些用于计算交叉区域的合理算法,特别是对于矩形的情况,如果你找到这样的三角形算法,这更有可能,那就足够了。两个矩形都可以分成两个三角形,分别是 1A+1B 和 2A+2B,然后你只需要运行这样的算法 4 次:1A-2A、1A-2B、1B-2A、1B-2B,将结果相加并那就是你的交叉路口的区域。

      编辑:对于数学方法(尽管这也来自图形),我认为https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm 可以在这里应用(因为两个矩形都是凸多边形,AB 和 BA 应该产生相同的结果)以找到相交多边形,然后剩下的任务就是计算那个多边形的面积(现在我认为它会是凸的,然后真的很容易)。

      【讨论】:

      • 感谢您的回答。我会查一下。但与此同时,CG 代表什么?
      • @prometeu 那部分很简单:CG = Computer Graphics :-)
      • 我将对 Sutherland-Hodgson 算法提出一些想法。你能告诉我你对我在 MBo 的回答中评论的近似值的看法吗?谢谢。
      • @prometeu 我认为这个想法适用于矩形是方形的并且近似值已经足够好的情况。但是,如果我们考虑“长”矩形,旋转可能会产生很大的影响,尤其是当旋转中心在另一个矩形之外时。
      • 再次感谢。它们几乎是方形的。但我写完了,也写了一个答案。
      【解决方案4】:

      由于您使用 Python,我认为 Shapely 包可以满足您的需求。

      【讨论】:

      • 确实如此。但是,出乎意料的是,它比我从互联网上收集的要慢 3 倍。此外,对于一个多边形,它显示的结果是我发现的两倍。我不知道为什么。对于矩形,它们的计算方式相同。
      【解决方案5】:

      我最终使用了作为这个函数实现的 Sutherland-Hodgman 算法:

      def clip(subjectPolygon, clipPolygon):
         def inside(p):
            return(cp2[0]-cp1[0])*(p[1]-cp1[1]) > (cp2[1]-cp1[1])*(p[0]-cp1[0])
      
         def computeIntersection():
            dc = [ cp1[0] - cp2[0], cp1[1] - cp2[1] ]
            dp = [ s[0] - e[0], s[1] - e[1] ]
            n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0]
            n2 = s[0] * e[1] - s[1] * e[0] 
            n3 = 1.0 / (dc[0] * dp[1] - dc[1] * dp[0])
            return [(n1*dp[0] - n2*dc[0]) * n3, (n1*dp[1] - n2*dc[1]) * n3]
      
         outputList = subjectPolygon
         cp1 = clipPolygon[-1]
      
         for clipVertex in clipPolygon:
            cp2 = clipVertex
            inputList = outputList
            outputList = []
            s = inputList[-1]
      
            for subjectVertex in inputList:
               e = subjectVertex
               if inside(e):
                  if not inside(s):
                     outputList.append(computeIntersection())
                  outputList.append(e)
               elif inside(s):
                  outputList.append(computeIntersection())
               s = e
            cp1 = cp2
         return(outputList)
      
      def PolygonArea(corners):
          n = len(corners) # of corners
          area = 0.0
          for i in range(n):
              j = (i + 1) % n
              area += corners[i][0] * corners[j][1]
              area -= corners[j][0] * corners[i][1]
          area = abs(area) / 2.0
          return area
      
      intersection = clip(rec1, rec2)
      intersection_area = PolygonArea(intersection)
      iou = intersection_area/(PolygonArea(rec1)+PolygonArea(rec2)-intersection_area)
      

      另一种较慢的方法(不知道是什么算法)可能是:

      from shapely.geometry import Polygon
      
      p1 = Polygon(rec1)
      p2 = Polygon(rec2)
      inter_sec_area = p1.intersection(rec2).area
      iou = inter_sec_area/(p1.area + p2.area - inter_sec_area)
      

      值得一提的是,在多边形较大的情况下(不是我的情况),shapely 模块的面积是第一种方法的两倍。我没有深入测试这两种方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-07-02
        • 2011-07-13
        • 2015-05-07
        • 1970-01-01
        • 2021-05-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多