【问题标题】:How to interpret the distance of the Iterative Closest Point (ICP) algorithm如何解释迭代最近点 (ICP) 算法的距离
【发布时间】:2019-08-15 16:46:38
【问题描述】:

我正在尝试开发一个应用程序,该应用程序使用 ICP 算法来查找在特定区域绘制的形状之间的相似性,但我不明白如何解释我在它结束时得到的距离。这是我使用的算法,仅从点列表开始: 其中 w 是旋转角度,T=(Tx, Ty) 是平移向量。它们也被描述为:
在哪里: 现在,我尝试绘制几个形状,但我所例外的是,如果形状非常相似,结果将接近 0。相反,通过这些形状,我得到了最终值 3515.334:
有了这个我得到了 6615.08:
最后,有了这(它们完全不同)我得到 454.54:
我误解了算法吗? 这是实现:

   private void icp (int z, ArrayList<Pair<Float,Float>> points) {
        ArrayList<Pair<Float,Float>> copia = segments.get(z);
        ArrayList<Pair<Float,Float>> copia2 = points;
        double x_trattino = 0.0;
        double y_trattino = 0.0;
        double x_trattino_primo = 0.0;
        double y_trattino_primo = 0.0;
        for (int i=0; i<copia.size(); i++) {
            x_trattino+=copia.get(i).first;
            y_trattino+=copia.get(i).second;
        }
        x_trattino = x_trattino*((double)1/copia.size());
        y_trattino = y_trattino*((double)1/copia.size());
        for (int i=0; i<copia2.size(); i++) {
            x_trattino_primo+=copia2.get(i).first;
            y_trattino_primo+=copia2.get(i).second;
        }
        x_trattino_primo = x_trattino_primo*((double)1/copia2.size());
        y_trattino_primo = y_trattino_primo*((double)1/copia2.size());
        double Sxx = 0.0;
        double Syy = 0.0;
        double Sxy = 0.0;
        double Syx = 0.0;
        int min = 0;
        if (copia.size()>copia2.size()) min = copia2.size(); else min = copia.size();
        for (int i=0; i<min; i++) {
            Sxx+=((copia.get(i).first-x_trattino)*(copia2.get(i).first-x_trattino_primo));
        }
        for (int i=0; i<min; i++) {
            Syy+=((copia.get(i).second-y_trattino)*(copia2.get(i).second-y_trattino_primo));
        }
        for (int i=0; i<min; i++) {
            Sxy+=((copia.get(i).first-x_trattino)*(copia2.get(i).second-y_trattino_primo));
        }
        for (int i=0; i<min; i++) {
            Syx+=((copia.get(i).second-y_trattino)*(copia2.get(i).first-x_trattino_primo));
        }
        double rotation = Math.toDegrees(Math.atan((Sxy-Syx)/(Sxx+Syy)));

        double Tx = x_trattino_primo - (x_trattino*Math.cos(rotation)-y_trattino*Math.sin(rotation));
        double Ty = y_trattino_primo - (x_trattino*Math.sin(rotation)+y_trattino*Math.cos(rotation));
        double eDist = 0.0;

        for (int i=0; i<min; i++) {
            eDist = (Math.pow(copia.get(i).first*Math.cos(rotation)-copia.get(i).second*Math.sin(rotation)+Tx-copia2.get(i).first, 2.0)+Math.pow(copia.get(i).first*Math.sin(rotation)+copia.get(i).second*Math.cos(rotation)+Ty-copia2.get(i).second, 2.0));
        }

        System.out.println("EDIST: "+eDist);
    }

【问题讨论】:

  • 您可以使用算法的开源实现来检查您的输出。看起来您的距离测量部分是原始点数的函数(通常,点越多,距离越大)。这似乎不是直接的相似性度量。
  • @JohnColeman 我所做的是将算法转换为代码,但我不明白它是否在检查形状之间的相似性。我可以想象看到结果是:最终结果越大,形状越相似。你对此有什么看法?
  • 你确定这是ICP吗?这里似乎没有任何最近点的迭代:您只是假设两个形状的第 i 个点之间的对应关系,然后将它们对齐一次。您不应该搜索最近的点,而不是假设对应关系是先验正确的吗?
  • @AndyTurner 我发现该算法用于检查两个形状的相似程度。我错了吗?
  • @Fabio 你在这里所做的是Procrustes analysis,而不是 ICP(具体来说,是没有缩放的正交 Procrustes)。

标签: java android algorithm math coordinates


【解决方案1】:

你犯的错误

  1. 不要使用 Math.toDegrees,完全跳过那个调用,变量 rotation 中的值应该是弧度而不是度数。
  2. 您写的是“eDist = ...”而不是“eDist += ...”。
  3. 您假设某些“定义点”应该在两种不同的形状中匹配。这可能是代码中最大的问题之一。假设您有两行,第一行分为两部分,而另一部分则没有。像这样

    .--------.---------.
    .------------------.
    

    您将尝试比较的是形状

    .--------.
    .------------------.
    

    这两个形状不会相似,因此距离不会很小。这意味着您可以拥有两个看起来非常相似的形状,但您的算法不会检测到这一点。举一个更复杂的例子来说明您要匹配的内容是,如果您在两个形状中有几个这样的点

    p1--p2--p3----p4----------p5---p6
    q1------q2----------------q3---q4
    

    您要匹配的是 p1 到 q1、p2 到 q2、p3 到 q3 和 p4 到 q4。这显然不能令人满意。

前进的道路

选择一种形状作为源,另一种作为目标。对于每个源点,找到目标中最近的点。现在您有一对点,它们是您应该在公式中使用的匹配点 P 和 P'。请注意,源中的多个点可以与目标中的同一点配对。重复这个过程,直到误差距离没有足够的改善。

还有其他接近 ICP 的方法,并且可能会出现几个问题。需要指出的一个问题是,如果您在我给您的直线示例中使用上述方法,则误差距离可能不会变小,因为中间点不靠近其他形状中的任何点。 所以上面的建议并不是详尽无遗的,但至少我给了你一个开始。

【讨论】:

  • 考虑到我的形状只由1段组成(所以整个形状都在1个ArrayList的点中,因为用户用单线绘制它们),就不会出现上面解释的问题,对吧?
  • “不要使用 Math.toDegrees”,使用 Math.atan2(y, x) 而不是 Math.atan(y/x)
  • @Fabio 我在答案中添加了一个示例,我认为问题仍然存在。
猜你喜欢
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
  • 2011-03-10
  • 2014-07-21
  • 2013-06-21
  • 2018-12-02
相关资源
最近更新 更多