【问题标题】:3D Connected Points Labeling based on Euclidean distances基于欧几里德距离的 3D 连接点标记
【发布时间】:2010-09-10 18:28:31
【问题描述】:

目前,我正在开展一个项目,该项目试图通过将连通性指定为最小欧几里德距离来对数据集中的 3d 点进行分组。我现在的算法只是简单的对原始洪水填充的 3d 改编。

size_t PointSegmenter::growRegion(size_t & seed, size_t segNumber) {
    size_t numPointsLabeled = 0;

    //alias for points to avoid retyping
    vector<Point3d> & points = _img.points;
    deque<size_t> ptQueue;
    ptQueue.push_back(seed);
    points[seed].setLabel(segNumber);
    while (!ptQueue.empty()) {
        size_t currentIdx = ptQueue.front();
        ptQueue.pop_front();
        points[currentIdx].setLabel(segNumber);
        numPointsLabeled++;
        vector<int> newPoints = _img.queryRadius(currentIdx, SEGMENT_MAX_DISTANCE, MATCH_ACCURACY);
        for (int i = 0; i < (int)newPoints.size(); i++) {
            int newIdx = newPoints[i];
            Point3d &newPoint = points[newIdx];
            if(!newPoint.labeled()) {
                newPoint.setLabel(segNumber);
                ptQueue.push_back(newIdx);
            }
        }
    }

    //NOTE to whoever wrote the other code, the compiler optimizes i++ 
    //to ++i in cases like these, so please don't change them just for speed :)
    for (size_t i = seed; i < points.size(); i++) {
        if(!points[i].labeled()) {
            //search for an unlabeled point to serve as the next seed.
            seed = i;
            return numPointsLabeled;
        }
    }
    return numPointsLabeled;
}

这里代码 sn-p 再次为新种子运行,_img.queryRadius() 是使用 ANN 库的固定半径搜索:

vector<int> Image::queryRadius(size_t index, double range, double epsilon) {
    int k = kdTree->annkFRSearch(dataPts[index], range*range, 0);
    ANNidxArray nnIdx = new ANNidx[k];
    kdTree->annkFRSearch(dataPts[index], range*range, k, nnIdx);
    vector<int> outPoints;
    outPoints.reserve(k);
    for(int i = 0; i < k; i++) {
        outPoints.push_back(nnIdx[i]);
    }
    delete[] nnIdx;
    return outPoints;
}

我对这段代码的问题是它运行 waaaaaaaaaaaaaaaay 对于大型数据集来说太慢了。如果我没记错的话,这段代码会搜索每一个点,搜索时间为 O(NlogN),时间复杂度为 (N^2*log(N))。

除此之外,如果我记得直接从 KD 树中删除,删除的成本相对较高,而且不删除点也会产生问题,因为每个点都可以被靠近它的每个邻居搜索数百次。

所以我的问题是,有没有更好的方法来做到这一点?尤其是随着数据集线性增长?

感谢您提供的任何帮助

编辑 我曾尝试使用像 dash-tom-bang 所说的简单排序列表,但结果比我以前使用的还要慢。我不确定它是否是实现,或者它只是太慢了,无法遍历每个点并检查欧几里得距离(即使只使用平方距离。

人们还有其他想法吗?老实说,我现在很难过。

【问题讨论】:

  • 看看en.wikipedia.org/wiki/K-means_clustering(k-means聚类)
  • k-means 聚类的问题是我不知道最终会得到多少个聚类,而且很多时候,我有两个大的平行平面靠在一起,它们需要因为平面之间的距离大于我的最大分割半径,所以要在不同的段中。
  • 你有多少分?对于这种特殊情况,K-means 通常非常糟糕,要找到即使在困难的数据集下也能正常工作的方法,您需要查看当前关于聚类的研究。这不是一件容易的事......但您可能不需要通用解决方案。你的应用是什么?你有具体的限制/特殊情况吗?
  • 感谢 Fevrier 的回复。我知道这是非常专业的,因为我正在处理航空 LIDAR 数据以检测建筑物和树木等。我正在做这个项目的研究,但我想我会在这里发帖,以防有人从事类似的工作。

标签: algorithm optimization complexity-theory computational-geometry


【解决方案1】:

我提出以下算法:

  1. 计算数据点的 3D Delaunay 三角剖分。

  2. 与步骤 3 结合使用时,删除所有长于阈值距离 O(N) 的边。

  3. 在结果图中找到大小为 O(N) 的连通分量,这是在 O(N α(N)) 中完成的。

瓶颈是步骤 1,根据此页面 http://www.ncgia.ucsb.edu/conf/SANTA_FE_CD-ROM/sf_papers/lattuada_roberto/paper.html,可以在 O(N2) 甚至 O(N log N) 中完成。但是它绝对不是一个 100 行的算法。

【讨论】:

  • @Alexandre:我查看了 cgal,但找不到实现的复杂性。有链接吗?
  • citeseerx.ist.psu.edu/viewdoc/… 终于找到了。开发这些算法的 INRIA 人员与将其实现到 CGAL 中的人相同。
  • 非常酷的解决方案,绝对让我对这个问题有了新的看法。谢谢!
【解决方案2】:

当我按照这些思路做某事时,我在数据集之外的某个地方选择了一个“原点”,并按所有点到该原点的距离对所有点进行排序。然后我在每一步都有一组小得多的点可供选择,而且我只需要穿过正在考虑的点周围的“洋葱皮”区域。您将检查相邻点,直到到最近点的距离小于您正在检查的范围的宽度。

虽然这对我来说效果很好,但可以通过沿一个轴对所有点进行排序(这表示“原点”无限远)然后再次检查点直到您的“搜索width" 超过了到目前找到的最近点的距离。

【讨论】:

  • 这是一个非常好的技巧,谢谢!您是如何组织数据集的?
  • 我想当时我把它全部塞进了一张地图中,但如果你不打算改变,只要一个排序的向量(带有适当仿函数的std::sort)也可以解决问题经常使用您的数据集。
【解决方案3】:

点应该组织得更好。为了更有效地搜索而不是vector&lt;Point3d&gt;,您需要某种哈希映射,其中哈希冲突意味着两个点彼此靠近(因此您可以使用哈希冲突来发挥自己的优势)。例如,您可以将空间划分为大小等于 SEGMENT_MAX_DISTANCE 的立方体,并使用哈希函数返回整数的三元组而不是整数,其中三元组的每个部分都计算为 point.&lt;corresponding_dimension&gt; / SEGMENT_MAX_DISTANCE

现在对于这个新集合中的每个点,您只搜索同一个立方体中的点,以及相邻的空间立方体中的点。这大大减少了搜索空间。

【讨论】:

  • 这会有点类似于网格解决方案吗?
  • 是的,您可以按点在 3D 网格中的位置对它们进行分组。所描述的哈希图的目的是,如果您有一个网格单元的位置,那么您立即拥有该单元的所有点,并且还拥有所有相邻的单元。如果你有一个点,那么你会立即知道它的网格单元格。
  • 也许我应该指出我的答案不是另一种解决方案,而是对您当前解决方案的改进。因为 _img.points 组织得更好,所以应该更改 _img.queryRadius 以使用它来仅查询那些是好的候选点。如果您不想将 _img.points 从 vector 更改为建议的结构,您仍然可以使用该向量,但点按网格分组,并使用一个结构来存储向量中每个段的边界数据。如果你愿意,我可以写一些示例代码。
  • ... 但是我需要 kdTree->annkFRSearch 的代码。
猜你喜欢
  • 1970-01-01
  • 2014-01-17
  • 2020-03-09
  • 1970-01-01
  • 2016-10-11
  • 2013-02-12
  • 2017-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多