实质上,体素是像素的三维扩展(“体积像素”),它们确实可以用于表示体积数据。
什么是体积数据
从数学上讲,体积数据可以看作是三维函数F(x,y,z)。在许多应用中,此函数是标量函数,即每个空间点(x,y,z)都有一个标量值。例如,在医疗应用中,这可以是某些组织的密度。为了在数字上表示这一点,一种常见的方法是简单地制作数据的切片:想象一下在(X,Y)平面中的图像,并将z值移动到具有一定数量的图像。如果切片彼此接近,则可以将图像显示为视频序列,例如在MRI扫描的维基页面上所见(
https://upload.wikimedia.org/wikipedia/commons/transcoded/4/44/Structural_MRI_animation.ogv/Structural_MRI_animation.ogv.360p.webm)。正如您所看到的,空间中的每个点都具有一个标量值,该值表示为灰度。
与其使用切片或视频,我们也可以使用体素来表示这些数据。不同于将2D平面分成像素的规则网格,我们现在将3D区域分成规则的体素网格。同样,每个体素都可以赋予一个标量值。然而,可视化这一点并不是那么容易:虽然我们可以给像素一个灰度值,但这对于体素来说并不起作用(我们只会看到盒子本身的颜色,而不是它的内部颜色)。事实上,这个问题是由于我们生活在一个3D世界中造成的:我们可以从第三个维度观察2D图像并完全观察它;但我们无法从第四个维度观察3D体素空间并完全观察它,因为我们没有第四个维度可以观察(除非您将时间视为第四个维度,即创建视频)。
因此,我们只能查看数据的一部分。一种方法是制作切片,如上所示。另一种方法是查看所谓的“等值面”:我们在3D空间中创建表面,使得每个点具有相同的标量值。对于医学扫描,这允许从体积数据中提取例如脑部(不仅作为切片,而是作为3D模型)。
最后,需要注意的是,
表面(网格、地形等)不是体积形状,它们是2D形状弯曲、扭曲、拉伸和变形以嵌入3D空间。理想情况下,它们代表一个体积对象的边界,但不一定如此(例如,地形数据可能不是封闭的网格)。使用体积数据表示表面的一种方法是确保表面再次成为某些函数的等值面。例如:F(x,y,z)= x ^ 2 + y ^ 2 + z ^ 2-R ^ 2可以表示以原点为中心,半径为R的球体。对于球体上的所有点(x',y',z'),F(x',y',z')= 0。更重要的是,对于球体内部的点,F <0,对于球体外部的点,F> 0。
创建这样一个函数的方法是创建一个
距离图,即创建体积数据,使得每个点F(x,y,z)表示到表面的距离。当然,表面是所有距离为0的点的集合(因此,与上述球体一样,值为0的等值面)。
如何实现
正如其他人所提到的,这确实取决于用途。本质上,数据可以以3D矩阵的形式给出。然而,这是巨大的!如果您想将分辨率加倍,您需要8倍的存储空间,因此通常这不是一个有效的解决方案。这对于较小的示例有效,但不会很好地扩展。
八叉树结构是目前最常用的存储结构。许多八叉树的实现和优化已经存在,因此请查看可以(重新)使用的内容。正如Andreas Kahler所指出的,稀疏体素八叉树是一种最新的方法。
八叉树允许更容易地导航到相邻的单元格、父单元格、子单元格等(现在我假设八叉树(或2D中的四叉树)的概念是已知的)。然而,如果许多叶子单元格位于最细分辨率处,则此数据结构将带来巨大的开销!那么,这比3D数组更好吗:它在某种程度上取决于您要处理的体积数据以及您要执行的操作。
如果数据用于表示表面,则八叉树通常会更好:如前所述,表面实际上并不是体积的,因此不需要许多体素来包含相关数据(因此:稀疏的八叉树)。回顾一下距离图,唯一相关的数据是具有值0的点。其他点也可以具有任何值,但这些值并不重要(在某些情况下,仍然考虑符号,以表示“内部”和“外部”,但仅需要表面时不需要该值本身)。
如何使用
如果您想知道“使用”是指如何呈现它们,那么您可以查看“ marching cubes”及其优化。MC将从体积数据创建一个三角形网格,以任何经典方式呈现。除了转换为三角形之外,您还可以查看体积渲染,以将“ 3D采样数据集”(即体素)呈现为这样(
https://en.wikipedia.org/wiki/Volume_rendering)。我必须承认我对体积渲染不太熟悉,所以现在就只留下维基链接了。