有没有办法比较两个几何形状(或任何两个更通用的数据结构),而不涉及公差时使用蛮力?
蛮力(即将每个对象的每个值与另一个对象的每个值进行比较)有效,但速度很慢,我无法使用它。
我尝试对数据进行排序并比较两个已排序的集合。速度很快,但只能零容忍。一旦我添加了容忍度,我就会迷失方向。问题是,当我比较时,两个值可以相同,而当我排序时,两个值可以不同。
以下是我的问题的一些细节。
在我的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)
,反之亦然,那么这两个形状是相同的。有时候我有数百个形状,每个都有数百行,所以蛮力解决方案对我来说不起作用。
我尝试了两种涉及有序集合的方法。两者都很快,因为比较两个已排序的集合比蛮力方式更快,但在某些条件下都失败了:
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
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
编辑:
通过COM从外部图形应用程序导入形状。形状可以像矩形一样简单,也可以像任何花式轮廓一样简单,内部有10个圆圈,20个内部形状和30个线条。它们代表带有孔和简单装饰的面板,有时它们具有锯齿形状,形成十几个边缘。
答案 0 :(得分:4)
将形状处理为多边形
将您的点数(每一行)转换为此行图像上的行(length,angle)
:
这确保了旋转/平移的不变性。如果您看到更多行angle=PI
将它们连接在一起以避免错误比较相同形状和不同采样,请尝试匹配两个形状的相同 CW / CCW 多边形缠绕规则。
找到起点
可以是最大或最小angle, length
...或angles+lengths
的特定顺序。因此,对一个多边形(cyclic shift)
的线进行重新排序,以便在可能的情况下从“相同点”比较您的形状。
比较 - 完全匹配
所以例如:
fabs (sum of all lengths of poly1 - sum of all lengths of poly2) <= 1e-3
如果不是形状不同。然后比较所有长度和角度。如果任何一个值的差异超过精度值,那么形状就不同了。
比较 - 尺寸无关紧要
计算两个多边形l1,l2
的周长,并调整比较poly2
的所有长度以匹配poly1
的周长,以便将poly2
的所有长度乘以value = l1/l2;
。在此之后使用bullet #3
比较 - 形状偏差仍然可以做正匹配(大小必须相同)
尝试将行数设置为相同的值(连接角度接近PI
的所有行)。那么周长应该“匹配”...... fabs(l1-l2)<=1e-3*l1
。您可以使用项目符号#4 比较
比较 - 尺寸和形状偏差仍可匹配
只需调整poly2
的大小以匹配poly1
的周边,如子弹#4 ,然后使用项目符号#5
如果找不到展位多边形的起点(项目符号#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)
<强> [注释] 强>
还有更快的比较方式,但在某些情况下可能会错过
如果你的形状必须以相同的方式定向(没有旋转不变性)
然后使用直线角度
如果您无法确保两个比较多边形的相同缠绕规则
然后你必须检查他们的摊位:
cmp (l11,l12,l13,l14,l15),(l21,l22,l23,l24,l25)
cmp (l11,l12,l13,l14,l15),(l25,l24,l23,l22,l21)
我知道答案有点含糊,但仍希望它至少有一点帮助...
答案 1 :(得分:1)
我有同样的问题。我计算了与距离加权的顶点的相邻矩阵。这会计算所有边长和对角线。然后,如果矩阵的每行或每列的模块与另一矩阵相同,则两个形状是相同的。对于公差,只需在启动前使用函数round()。复杂度为O(n2 / 2),因为您只需要计算对称矩阵的一半。问题是我无法检测是否翻转了一个形状。
答案 2 :(得分:1)
我不确定您要如何解决此问题。您想深入了解,或者只想找到解决方案。我可以建议您使用一个称为“ matchShapes”的OpenCV函数。此函数基于Hu矩,对于刚性形状具有良好的性能。提取目标和主要轮廓后,请使用下面的代码进行比较。
dif = cv.matchShapes(Contour1, Contour2, 1, 0, 0)
较小的“ dif”值意味着轮廓之间的相似度更高。