如何比较两种形状?

时间:2014-03-03 23:38:03

标签: algorithm vba comparison geometry shapes

有没有办法比较两个几何形状(或任何两个更通用的数据结构),而不涉及公差时使用蛮力?

蛮力(即将每个对象的每个值与另一个对象的每个值进行比较)有效,但速度很慢,我无法使用它。

我尝试对数据进行排序并比较两个已排序的集合。速度很快,但只能零容忍。一旦我添加了容忍度,我就会迷失方向。问题是,当我比较时,两个值可以相同,而当我排序时,两个值可以不同。

以下是我的问题的一些细节。

在我的Excel VBA加载项中,我有一组Shape个对象,这些对象由Line个对象组成,每个对象由两个Point个对象组成。加载项通过COM扫描CAD绘图并创建Shape个对象的集合。

简化版可以生成:

            Shape 1     Shape 2
Point 1    0.0  5.0    0.0  4.9
Point 2    4.9  0.0    5.1  0.0
Point 3    5.0  5.0    5.0  5.0

我需要找到哪些形状与哪些形状相同,其中相同的形状具有相同的形状,大小和方向,但不是相同的位置(到目前为止它是微不足道的)加上或减去公差(现在不是那么简单!)

Point.IsIdenticalTo(OtherPoint)定义为:

Function IsIdenticalTo(OtherPoint As Point) As Boolean
  IsIdenticalTo = Abs(X - OtherPoint.X) < Tolerance And Abs(Y - OtherPoint.Y) < Tolerance
End Function

Shape.IsIdenticalTo(OtherShape)的强力实施有效,但速度太慢:如果每个Line(I)具有相同的OtherShape.Line(J),反之亦然,那么这两个形状是相同的。有时候我有数百个形状,每个都有数百行,所以蛮力解决方案对我来说不起作用。

我尝试了两种涉及有序集合的方法。两者都很快,因为比较两个已排序的集合比蛮力方式更快,但在某些条件下都失败了:

  1. SortedValues集合包含所有行的所有X和Y值。值已排序,因此有关值是X还是Y的信息将丢失。我已经使用这种方法几个月没有问题,但是例如当两个形状之间的唯一差异在点(10, 20)(20, 10)之间时,它就失败了。我将线条角度添加到值列表中,事情已经改进,但仍然存在这种方法失败的情况,因为当值一起排序时,某些信息会丢失。在上面的示例中,此方法适用于以下集合:

    Shape 1     Shape 2
      0.0         0.0
      0.0         0.0
      4.9         4.9
      5.0         5.0
      5.0         5.0
      5.0         5.1
    
  2. SortedLines集合包含逆时针排序的所有行,并从最接近原点的点开始。这种方法不会丢失任何信息,但在上面的示例中失败,因为排序算法不符合相等比较。如果公差为0.5,则它们应该相同,但排序算法会生成如下所示的集合。事情变得更加困难,因为我的形状包含子形状,因此每个形状上有许多起点。

            Shape 1     Shape 2
    Point 1    4.9  0.0    0.0  4.9
    Point 2    5.0  5.0    5.1  0.0
    Point 3    0.0  5.0    5.0  5.0
    
  3. 编辑:

    通过COM从外部图形应用程序导入形状。形状可以像矩形一样简单,也可以像任何花式轮廓一样简单,内部有10个圆圈,20个内部形状和30个线条。它们代表带有孔和简单装饰的面板,有时它们具有锯齿形状,形成十几个边缘。

3 个答案:

答案 0 :(得分:4)

  1. 将形状处理为多边形

    将您的点数(每一行)转换为此行图像上的行(length,angle)

    polygon representation

    这确保了旋转/平移的不变性。如果您看到更多行angle=PI将它们连接在一起以避免错误比较相同形状和不同采样,请尝试匹配两个形状的相同 CW / CCW 多边形缠绕规则。

  2. 找到起点

    可以是最大或最小angle, length ...或angles+lengths的特定顺序。因此,对一个多边形(cyclic shift)的线进行重新排序,以便在可能的情况下从“相同点”比较您的形状。

  3. 比较 - 完全匹配

    • 行数必须相同
    • 周长必须相同+/-一些准确度

    所以例如:

    fabs (sum of all lengths of poly1 - sum of all lengths of poly2) <= 1e-3
    

    如果不是形状不同。然后比较所有长度和角度。如果任何一个值的差异超过精度值,那么形状就不同了。

  4. 比较 - 尺寸无关紧要

    计算两个多边形l1,l2的周长,并调整比较poly2的所有长度以匹配poly1的周长,以便将poly2的所有长度乘以value = l1/l2; 。在此之后使用bullet #3

  5. 进行比较
  6. 比较 - 形状偏差仍然可以做正匹配(大小必须相同)

    尝试将行数设置为相同的值(连接角度接近PI的所有行)。那么周长应该“匹配”...... fabs(l1-l2)<=1e-3*l1。您可以使用项目符号#4 比较

  7. 比较 - 尺寸和形状偏差仍可匹配

    只需调整poly2的大小以匹配poly1的周边,如子弹#4 ,然后使用项目符号#5

  8. 如果找不到展位多边形的起点(项目符号#2

    然后你必须检查所有的起点变化,所以如果你的多边形有5号展位:

        poly1: l11,l12,l13,l14,l15
        poly2: l21,l22,l23,l24,l25
    

    然后你必须比较所有5种组合(除非你发现更快的比赛):

        cmp (l11,l12,l13,l14,l15),(l21,l22,l23,l24,l25)
        cmp (l11,l12,l13,l14,l15),(l22,l23,l24,l25,l21)
        cmp (l11,l12,l13,l14,l15),(l22,l23,l24,l25,l21)
        cmp (l11,l12,l13,l14,l15),(l23,l24,l25,l21,l22)
        cmp (l11,l12,l13,l14,l15),(l24,l25,l21,l22,l23)
        cmp (l11,l12,l13,l14,l15),(l25,l21,l22,l23,l24)
    

    <强> [注释]

    1. 还有更快的比较方式,但在某些情况下可能会错过

      • 您可以比较直线,角度的直方图
      • 你可以使用神经网络(我不喜欢它们,但它们非常适合这样的分类)
    2. 如果你的形状必须以相同的方式定向(没有旋转不变性)

      然后使用直线角度

    3. 而不是顶角
    4. 如果您无法确保两个比较多边形的相同缠绕规则

      然后你必须检查他们的摊位:

      cmp (l11,l12,l13,l14,l15),(l21,l22,l23,l24,l25)
      cmp (l11,l12,l13,l14,l15),(l25,l24,l23,l22,l21)
      
    5. 我知道答案有点含糊,但仍希望它至少有一点帮助...

答案 1 :(得分:1)

我有同样的问题。我计算了与距离加权的顶点的相邻矩阵。这会计算所有边长和对角线。然后,如果矩阵的每行或每列的模块与另一矩阵相同,则两个形状是相同的。对于公差,只需在启动前使用函数round()。复杂度为O(n2 / 2),因为您只需要计算对称矩阵的一半。问题是我无法检测是否翻转了一个形状。

答案 2 :(得分:1)

我不确定您要如何解决此问题。您想深入了解,或者只想找到解决方案。我可以建议您使用一个称为“ matchShapes”的OpenCV函数。此函数基于Hu矩,对于刚性形状具有良好的性能。提取目标和主要轮廓后,请使用下面的代码进行比较。

dif = cv.matchShapes(Contour1, Contour2, 1, 0, 0)

较小的“ dif”值意味着轮廓之间的相似度更高。