【问题标题】:How to handle 3D voxels efficiently?如何有效地处理 3D 体素?
【发布时间】:2012-03-22 19:14:13
【问题描述】:

我有一个包含数百万个点的 3D 点云。我想将这些点存储在 3D 体素空间中。沿坐标轴的体素数超过3000(x)、4000(y)、1500(z),共计3000*4000*1500体素。我需要存储在体素中;最大点数、最小高度、最大高度和质心。然而,90% 的体素是空的。所以它需要大量的内存来存储它。实际上,我想稍后搜索每个体素的 26 个相邻体素。那么,在体素空间中存储这些数据并有效访问这些数据的最佳方法是什么?

创建一个多维数组,在性能方面不是最好的解决方案...请任何提示?

【问题讨论】:

  • 在 90% 为空时,您仍有 1.800.000.000 个体素。无论如何,这不会飞。您可以沿一维存储体素的运行,但查找成本很高。
  • @leftaroundabout,它可能是 4D 体素,还是不是?
  • @usr voxel = 体积像素,体积定义为 3D
  • 体积定义为 3D。至少根据维基百科。
  • 使用几何数据时,0D 是空间中的任意点,可以驻留在任意维度空间中;即使是用作位置而不是具有大小的方向的vector2,vector3等也是0D空间。另一个词 0D 空间是空间中的任意点。 1D 空间是两个点(距离)之间的连接,它可以是空间中的 2D 或 3D 矢量,其中方向和/或大小被认为是有效的重要信息。另一个词 1D 是到语言环境或两点之间的距离或测量场...

标签: c++ 3d computational-geometry


【解决方案1】:

这类数据的经典数据结构是kd-Treesoctrees.

另外,您绝对应该看看在 CGAL 中实现的 spatial searching and sorting 数据结构。

【讨论】:

  • 什么是最好的数据结构,kd 树还是八叉树?我们可以使用带有八叉树的体素数据结构还是....对不起,我对这些数据结构不清楚。
  • @user1286780 在您最初的问题中,您只询问了体素数据结构,因此我不会将此作为单独的答案。但是您对此答案的评论表明您对其他数据结构持开放态度。既然你说你想看邻居,你可能想看看我们 2012 年在机器人软件工程杂志 (JOSER) 上发表的论文“Comparison of nearest-neighbor-search strategy and implementations for Effective shape registration”, robotik.informatik.uni-wuerzburg.de/telematics/download/…
【解决方案2】:

如果它真的“只是”几百万个点,那么 90% 以上的体素将是空的。我会尝试从体素坐标到点的散列多图(C++ 11 中的std::unordered_multimap)。这给了你 O(1) 查找,就像一个数组。虽然它会带来相当多的开销,但它可能是最好的折衷方案。

为此,您唯一需要的是体素类中的相等比较和模板特化std::hash<voxel>。您不会以任何自动方式实现“最大点数”,但这真的有用吗?

【讨论】:

  • 不过,查找邻居的成本会很高。
  • @usr:不是真的。正如我所说,对于 any 点,查找是 O (1)。邻居并不比其他任何点都快。
  • 其中有 26 个,这使得 O(1) 代价高昂。
  • 是的......但你并没有绕过这些。在基于树的结构中,查找将有一些 O (ld n) 在其中,对于数百万个点来说也是二十几。您希望通过仅在树中彼此靠近的查找来解决此问题,但这在数学上是不可能的,因为there exists no homeomorphism from ℝ³ to one dimension,这也意味着例如然而,位于相邻体素中的 k-d 树将被树中高处的平面隔开。
  • 不要误会我的意思:我同意八叉树和 k-d 树在您没有固定的离散体素栅格时是正确的选择,因为这样您需要考虑 按距离 的相邻点,这对于散列是不可能的。但是,一旦有了栅格,从而有了离散度量,就可以使用散列,而且效果更好。
【解决方案3】:

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

举例说明:

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 使用这种方法,t_voxel_collection 代表一维。引入维度的简单方法是使用容器,例如std::vector&lt;std::vector&lt;t_voxel_collection&gt; &gt;。类似于t_voxel_collection 的实现,可能有更优化的方式来表示集合的一个维度,这取决于您希望如何平衡内存、cpu 等。其他人提到了比我消耗更少内存的替代方案(尽管我的方案会节省很多),但是使用我的方法查找非常快——对于这么大的数据集,平衡很重要。
  • 谢谢贾斯汀。我还想了解以下情况下的查找。
  • 我在体素 (a) 中有一个平面,我想找到我的平面相交的 (a) 的最近体素(没有所有 26 个体素)。但是如果这种情况我希望射线法更好,这个平面不是垂直或水平的。请问您也可以对此提出任何想法吗?
  • @user1286780 你试过 Bresenham 的线算法(3D)吗? stackoverflow.com/questions/5365019/ray-voxel-intersection
【解决方案4】:

无论你做什么,你都会变得不卡,即使你为你的稀疏网格找到了一个完美的内存布局——这仍然需要太多的内存。真正的问题是能够有效地将其存储在磁盘上并智能地缓存感兴趣的区域。

谢天谢地,Field3D 就是为此而开发的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-05
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    相关资源
    最近更新 更多