如何高效处理3D体素?

5
我有一个拥有数百万个点的3D点云。我想将这些点存储在3D体素空间中。沿着坐标轴的体素数量分别超过3000(x),4000(y),1500(z),共计3000 * 4000 * 1500体素。我需要在一个体素中存储最大数量的点,最小高度,最大高度和质心。然而,90%的体素是空的。因此,存储这些数据需要大量内存。实际上,我想以后查找每个体素的26个相邻体素。那么,在体素空间中存储这些数据并有效地访问它们的最佳方法是什么?
创建多维数组不是性能最好的解决方案...请给出任何提示?

4
即使有90%的空间,您仍然拥有18亿个体素。这在任何情况下都是不可行的。您可以沿一个维度存储一系列的体素,但查找成本很高。 - Anteru
1
@leftaroundabout,它可能是一个4D体素,还是不是? - usr
1
@usr 体素是三维图像元素,由定义可知,体积是三维的。 - pezcode
1
体积并非被定义为三维的。至少根据维基百科的解释。 - usr
作为最后的观察,考虑到纯数学和科学模型,体积的理解是指在特定空间区域内物质的数量。因此,体积可以在任何空间维度中理解。 - Francis Cugler
显示剩余5条评论
4个回答

3

这个问题使用哪种数据结构最好,kd树还是八叉树?我们可以在八叉树中使用体素数据结构吗,或者……抱歉,我对这些数据结构没有清楚的想法。 - user1286780
1
@user1286780,在您最初的问题中,您只询问了有关体素数据结构的问题,因此我不会将其作为单独的答案。但是,您对此答案的评论表明您对其他数据结构持开放态度。由于您说要查看邻居,您可能需要查看我们2012年在《机器人软件工程杂志》(JOSER)上发表的论文“用于有效形状配准的最近邻搜索策略和实现的比较”,网址为https://robotik.informatik.uni-wuerzburg.de/telematics/download/joser2012.pdf。 - josch

2
如果真的只有数百万个点,那么超过90%的体素将是空的。我建议使用哈希多映射(std::unordered_multimap在C++11中)从体素坐标到点的映射。这样就可以像数组一样O(1)查找。虽然这种方法有很多开销,但它可能是最好的折衷方案。
为了使此方法有效,您需要在体素类中进行相等比较,并进行模板特化std::hash<voxel>。您不会以任何自动方式实现“最大点数”,但这真的有用吗?

查找邻居将会耗费很大代价。 - usr
@usr:不是很快。正如我所说,查找时间复杂度为 O(1),适用于任何点。相邻点并不比其他点更快。 - leftaroundabout
它们总共有26个,这导致了O(1)的高昂开销。 - usr
1
是的...但你无法避免那些。在基于树形结构的系统中,查找将包含一些_O_(ld_n_),对于数百万个点来说也是二十多个。你希望通过只在树中靠近彼此的查找来解决这个问题,但这在数学上是不可能的,因为从ℝ³到一维中不存在同胚映射,这也意味着例如_k_-d树中的某些节点位于相邻的体素中,但仍然会被一个高层的平面隔离。 - leftaroundabout
1
别误会我的意思:我同意当你没有固定的离散体素光栅时,八叉树和_k_-d树是正确的选择,因为这时你需要考虑到相邻点之间的距离,而哈希表无法做到这一点。但是一旦你有了一个光栅,也就有了一个离散度量,使用哈希表是可能的,而且更好。 - leftaroundabout
看起来你真的很懂。+1! - usr

1

一种方法是使用集合中的数据来支持您的实际数据。

举个例子:

struct t_voxel {
  size_t nPoints, minHeight, maxHeight, centorid;
};

struct t_voxel_id {
  uint16_t index;
};

// one dimension
class t_voxel_collection {
  // the actual voxel data needed for the indices represented by the collection of voxelId
  std::vector<t_voxel> d_voxel;
  // here, empty voxel is designated by t_voxel.index = 0
  // this collection is your primary array representation
  // these elements just refer to a unique or shared index in this->d_voxel
  std::vector<t_voxel_id> d_voxelId;
public:
  // >> the interface to access and set, which abstracts the backing collection.
  // and prohibits the client from accessing the actual data.

  t_voxel get(const size_t& idx) const {
    return this->d_voxel[this->d_voxelId[idx].index];
  }
  // ...
};

通过这种方式,您可以实现大幅度降低内存消耗(假设您看到了这个方向)。

这不是一个完整的答案,但在这种情况下可能会有所帮助。

根据您的使用情况,还有几种方法可以进一步优化和共享此集合中的体素数据。


谢谢你的想法。希望你所解释的方法能够帮助解决内存分配问题。我想知道获取3D中相邻的26个体素的高效方法!!!你有什么想法吗? - user1286780
通过这种方法,@user1286780,t_voxel_collection 表示一维。引入维度的简单方法是使用一个容器,例如 std::vector<std::vector<t_voxel_collection>>。与 t_voxel_collection 的实现类似,可能有更优化的方式来表示集合的维度,这取决于您想如何平衡内存、CPU 等。其他人提出了比我使用的消耗更少内存的替代方案(尽管在这种场景下我的方案可以节省很多),但使用我的方法查找非常快速 -- 对于这么大的数据集,平衡很重要。 - justin
谢谢Justin。我还想了解一下以下情况中的查找方法。 - user1286780
我有一个体素(a)中的平面,我想找到与其相交的最近体素(不包括所有26个体素)。但是,如果这个平面不是竖直或水平的话,我希望使用射线法更好。请问您是否也能提供这个问题的任何建议? - user1286780
@user1286780 你尝试过使用Bresenham的线算法(3D)吗?https://dev59.com/4lXTa4cB1Zd3GeqP1GJe - justin
这只是用于线检测,但我有一个平面(斜面),所以我想获取所有属于该平面的体素。 - user1286780

1
无论你做什么,你都会变得不再卡顿,即使你为你的稀疏网格找到了完美的内存布局 - 仍然需要太多的内存。真正的问题是能够有效地存储它并智能缓存感兴趣的区域。
值得庆幸的是,Field3D就是为此而开发的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接