基于欧几里德距离的三维连通点标记

时间:2010-09-10 18:28:32

标签: algorithm optimization complexity-theory computational-geometry

目前,我正在研究一个项目,该项目试图通过将连通性指定为最小欧氏距离来对数据集中的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;
}

再次为新种子运行此代码段,_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;
}

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

除此之外,如果我从KD树中记得,删除是相对昂贵的,但也不会删除点会产生问题,因为每个点都可以被接近它的每个邻居搜索数百次。

所以我的问题是,有更好的方法吗?特别是以与数据集线性增长的方式?

感谢您提供的任何帮助

修改 我曾尝试使用像dash-tom-bang这样的简单排序列表,但结果甚至比我之前使用的更慢。我不确定它是否是实现,或者只是太慢而无法迭代每个点并检查欧氏距离(即使只是使用平方距离。

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

3 个答案:

答案 0 :(得分:3)

我提出以下算法:

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

  2. 当与步骤3结合使用时,移除长度超过阈值距离O(N)的所有边缘。

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

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

答案 1 :(得分:2)

当我沿着这些线做某事时,我在某个地方的数据集之外选择了一个“原点”,并根据它们到该原点的距离对所有点进行了分类。然后我在每一步都有一个小得多的点可供选择,我只需要经过考虑点的“洋葱皮”区域。您将检查相邻点,直到距离最近点的距离小于您正在检查的范围的宽度。

虽然这对我来说效果很好,但是可以通过沿着一个轴排序所有点(这将代表“起点”无限远)来实现类似的版本,然后再次检查点直到“搜索” width“超出到目前为止找到的最近点的距离。

答案 2 :(得分:2)

应该更好地组织点数。要更有效地搜索而不是vector<Point3d>,您需要某种哈希映射,其中哈希冲突意味着两个点彼此接近(因此您使用哈希冲突对您有利)。例如,您可以将空间划分为大小等于SEGMENT_MAX_DISTANCE的多维数据集,并使用哈希函数返回三元组的int而不仅仅是int,其中三元组的每个部分都计算为point.<corresponding_dimension> / SEGMENT_MAX_DISTANCE

现在,对于此新集合中的每个点,您只搜索同一个多维数据集中的点以及相邻的空间多维数据集。这大大减少了搜索空间。