我正在尝试计算3D numpy数组的体积(或表面积)。在许多情况下,体素是各向异性的,并且我在每个方向上具有像素到厘米的转换因子。
有没有人知道找一个工具包或包来做上述事情的好地方?
目前,我有一些内部代码,但我希望在准确性方面升级到更具工业实力的东西。
Edit1:这是一些(差)样本data。这比典型的球体小得多。我可以在生成它时添加更好的数据!它在(自我)肿瘤脑肿瘤中。
答案 0 :(得分:5)
一种选择是使用VTK
。 (我将在这里使用tvtk
python绑定...)
至少在某些情况下,获取等值面内的区域会更准确。
此外,就表面积而言,tvtk.MassProperties
也会计算表面积。它是mass.surface_area
(下面的代码中带有mass
对象。)
import numpy as np
from tvtk.api import tvtk
def main():
# Generate some data with anisotropic cells...
# x,y,and z will range from -2 to 2, but with a
# different (20, 15, and 5 for x, y, and z) number of steps
x,y,z = np.mgrid[-2:2:20j, -2:2:15j, -2:2:5j]
r = np.sqrt(x**2 + y**2 + z**2)
dx, dy, dz = [np.diff(it, axis=a)[0,0,0] for it, a in zip((x,y,z),(0,1,2))]
# Your actual data is a binary (logical) array
max_radius = 1.5
data = (r <= max_radius).astype(np.int8)
ideal_volume = 4.0 / 3 * max_radius**3 * np.pi
coarse_volume = data.sum() * dx * dy * dz
est_volume = vtk_volume(data, (dx, dy, dz), (x.min(), y.min(), z.min()))
coarse_error = 100 * (coarse_volume - ideal_volume) / ideal_volume
vtk_error = 100 * (est_volume - ideal_volume) / ideal_volume
print 'Ideal volume', ideal_volume
print 'Coarse approximation', coarse_volume, 'Error', coarse_error, '%'
print 'VTK approximation', est_volume, 'Error', vtk_error, '%'
def vtk_volume(data, spacing=(1,1,1), origin=(0,0,0)):
data[data == 0] = -1
grid = tvtk.ImageData(spacing=spacing, origin=origin)
grid.point_data.scalars = data.T.ravel() # It wants fortran order???
grid.point_data.scalars.name = 'scalars'
grid.dimensions = data.shape
iso = tvtk.ImageMarchingCubes(input=grid)
mass = tvtk.MassProperties(input=iso.output)
return mass.volume
main()
这会产生:
Ideal volume 14.1371669412
Coarse approximation 14.7969924812 Error 4.66731094565 %
VTK approximation 14.1954890878 Error 0.412544796894 %
答案 1 :(得分:1)
体素将是相当简单的常规多面体,不是吗?计算每一个的体积并求它们。
答案 2 :(得分:1)
traits.trait_errors.TraitError: The 'input' trait of an ImageMarchingCubes instance is 'read only'.
以下是所需的更改以及显示如何修复它的差异。
修改代码:import numpy as np
from tvtk.api import tvtk
from tvtk.common import configure_input
def main():
# Generate some data with anisotropic cells...
# x,y,and z will range from -2 to 2, but with a
# different (20, 15, and 5 for x, y, and z) number of steps
x, y, z = np.mgrid[-2:2:20j, -2:2:15j, -2:2:5j]
r = np.sqrt(x**2 + y**2 + z**2)
dx, dy, dz = [np.diff(it, axis=a)[0, 0, 0] for it, a in zip(
(x, y, z), (0, 1, 2))]
# Your actual data is a binary (logical) array
max_radius = 1.5
data = (r <= max_radius).astype(np.int8)
ideal_volume = 4.0 / 3 * max_radius**3 * np.pi
coarse_volume = data.sum() * dx * dy * dz
est_volume = vtk_volume(data, (dx, dy, dz), (x.min(), y.min(), z.min()))
coarse_error = 100 * (coarse_volume - ideal_volume) / ideal_volume
vtk_error = 100 * (est_volume - ideal_volume) / ideal_volume
print('Ideal volume', ideal_volume)
print('Coarse approximation', coarse_volume, 'Error', coarse_error, '%')
print('VTK approximation', est_volume, 'Error', vtk_error, '%')
def vtk_volume(data, spacing=(1, 1, 1), origin=(0, 0, 0)):
data[data == 0] = -1
grid = tvtk.ImageData(spacing=spacing, origin=origin)
grid.point_data.scalars = data.T.ravel() # It wants fortran order???
grid.point_data.scalars.name = 'scalars'
grid.dimensions = data.shape
iso = tvtk.ImageMarchingCubes()
configure_input(iso, grid) # <== will work
# iso = tvtk.ImageMarchingCubes(input=grid)
mass = tvtk.MassProperties()
configure_input(mass, iso)
# mass = tvtk.MassProperties(input=iso.output)
return mass.volume
if __name__ == '__main__':
main()
我做的改变的差异
2a3,4
> from tvtk.common import configure_input
>
6c8
< # x,y,and z will range from -2 to 2, but with a
---
> # x,y,and z will range from -2 to 2, but with a
8c10
< x,y,z = np.mgrid[-2:2:20j, -2:2:15j, -2:2:5j]
---
> x, y, z = np.mgrid[-2:2:20j, -2:2:15j, -2:2:5j]
11c13,14
< dx, dy, dz = [np.diff(it, axis=a)[0,0,0] for it, a in zip((x,y,z),(0,1,2))]
---
> dx, dy, dz = [np.diff(it, axis=a)[0, 0, 0] for it, a in zip(
> (x, y, z), (0, 1, 2))]
24,26c27,30
< print 'Ideal volume', ideal_volume
< print 'Coarse approximation', coarse_volume, 'Error', coarse_error, '%'
< print 'VTK approximation', est_volume, 'Error', vtk_error, '%'
---
> print('Ideal volume', ideal_volume)
> print('Coarse approximation', coarse_volume, 'Error', coarse_error, '%')
> print('VTK approximation', est_volume, 'Error', vtk_error, '%')
>
28c32
< def vtk_volume(data, spacing=(1,1,1), origin=(0,0,0)):
---
> def vtk_volume(data, spacing=(1, 1, 1), origin=(0, 0, 0)):
31c35
< grid.point_data.scalars = data.T.ravel() # It wants fortran order???
---
> grid.point_data.scalars = data.T.ravel() # It wants fortran order???
35,36c39,44
< iso = tvtk.ImageMarchingCubes(input=grid)
< mass = tvtk.MassProperties(input=iso.output)
---
> iso = tvtk.ImageMarchingCubes()
> configure_input(iso, grid) # <== will work
> # iso = tvtk.ImageMarchingCubes(input=grid)
> mass = tvtk.MassProperties()
> configure_input(mass, iso)
> # mass = tvtk.MassProperties(input=iso.output)
39c47,49
< main()
---
>
> if __name__ == '__main__':
> main()
详细的变更清单:
input=
构造函数ImageMarchingCubes
kwarg
input=
构造函数MassProperties
kwargs