目前,我正在开展一个项目,该项目试图通过将连通性指定为最小欧几里德距离来对数据集中的 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;
}
再次为新种子运行此代码片段,_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 所说的简单排序列表,但结果甚至比我以前使用的要慢。我不确定它是否是实现,或者它只是太慢了,无法遍历每个点并检查欧几里得距离(即使只使用平方距离。
人们可能还有其他想法吗?我现在真的很难过。