You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何将二值化2D CT图像数组转换为可打印3D模型(STL)

我来帮你解决这个问题!你手里的二值CT体数据转3D网格(STL)的需求,其实可以通过VTK、PyVista这类工具轻松实现——SimpleITK本身确实不直接支持导出STL,但可以配合其他库完成,或者直接用更适合网格生成的工具。下面给你几个可行的方案,尤其是你已经在尝试VTK,我会补全完整的实现代码:

二值CT体数据转3D STL模型的实现方案

一、基于VTK的完整实现(适配你已有的代码基础)

VTK是处理体数据和网格的经典工具,Marching Cubes算法可以从二值体数据中提取出等值面,进而生成STL。这里给你补全完整的代码流程:

步骤1:导入依赖并处理numpy数组

首先把你的二值numpy数组转换成VTK能识别的图像格式,注意调整轴的顺序适配VTK的坐标体系:

import numpy as np
import vtk
from vtk.util.numpy_support import numpy_to_vtk

# 假设你的二值CT数组为ct_volume,shape=[512,512,586],像素值0/255
# 先把255转为1(可选,不转的话等值面设为127即可)
ct_volume = (ct_volume == 255).astype(np.int16)

# 调整轴顺序:numpy的[Y,X,Z]转为VTK的[X,Y,Z]
vtk_compatible_volume = ct_volume.transpose(1, 0, 2)

# 创建VTK图像数据对象
image_data = vtk.vtkImageData()
image_data.SetDimensions(vtk_compatible_volume.shape)
# 关键:设置体素间距(根据你的CT实际分辨率填写,比如1mm×1mm×1mm)
image_data.SetSpacing(1.0, 1.0, 1.0)
image_data.SetOrigin(0.0, 0.0, 0.0)

# 将numpy数组转为VTK数组并赋值给图像数据
vtk_array = numpy_to_vtk(vtk_compatible_volume.flatten(), deep=True, array_type=vtk.VTK_SHORT)
image_data.GetPointData().SetScalars(vtk_array)

步骤2:用Marching Cubes提取等值面

二值数据的等值面取0.5(如果是0/1的数组),如果保留0/255则取127:

marching_cubes = vtk.vtkMarchingCubes()
marching_cubes.SetInputData(image_data)
marching_cubes.SetValue(0, 0.5)  # 提取值为0.5的等值面
marching_cubes.Update()

步骤3:优化网格并保存为STL

提取后的网格可能有冗余点或小面,用清理工具优化,可选平滑处理,最后导出STL:

# 清理网格:去除重复点、无用单元
clean_filter = vtk.vtkCleanPolyData()
clean_filter.SetInputConnection(marching_cubes.GetOutputPort())
clean_filter.Update()

# 可选:平滑网格,提升模型美观度
smooth_filter = vtk.vtkSmoothPolyDataFilter()
smooth_filter.SetInputConnection(clean_filter.GetOutputPort())
smooth_filter.SetNumberOfIterations(20)  # 迭代次数可按需调整
smooth_filter.SetRelaxationFactor(0.1)
smooth_filter.Update()

# 导出STL文件
stl_writer = vtk.vtkSTLWriter()
stl_writer.SetFileName("ct_3d_model.stl")
stl_writer.SetInputConnection(smooth_filter.GetOutputPort())
stl_writer.SetFileTypeToBinary()  # 二进制格式体积更小
stl_writer.Write()

二、基于PyVista的简化实现(代码更简洁)

PyVista是VTK的高层封装,用更少的代码就能完成相同的任务,非常适合快速开发:

import numpy as np
import pyvista as pv

# 处理你的二值CT数组
ct_volume = (ct_volume == 255).astype(np.int16)

# 创建均匀网格对象,设置体素间距
grid = pv.UniformGrid()
grid.dimensions = ct_volume.shape
grid.spacing = (1.0, 1.0, 1.0)  # 按实际CT分辨率调整
grid.point_data["values"] = ct_volume.flatten(order="F")

# 提取等值面并保存为STL
surface = grid.contour(isosurfaces=[0.5])
surface.save("ct_3d_model_pyvista.stl")

三、SimpleITK配合其他工具的方案

如果你坚持用SimpleITK处理图像,可以先把SimpleITK图像转成numpy数组,再用上面的VTK/PyVista方法生成STL:

import SimpleITK as sitk
import numpy as np
import pyvista as pv

# 从SimpleITK读取图像(或直接用你已有的sitk图像)
sitk_image = sitk.ReadImage("your_ct_data.nii.gz")
# 转换为numpy数组(注意SimpleITK的数组顺序是[Z,Y,X])
ct_volume = sitk.GetArrayFromImage(sitk_image)
# 调整轴顺序适配PyVista
ct_volume = ct_volume.transpose(2, 1, 0)

# 后续步骤和PyVista方案一致...
grid = pv.UniformGrid()
grid.dimensions = ct_volume.shape
grid.spacing = sitk_image.GetSpacing()  # 直接从SimpleITK获取体素间距,更准确!
grid.point_data["values"] = ct_volume.flatten(order="F")
surface = grid.contour(isosurfaces=[0.5])
surface.save("ct_3d_model_sitk.stl")

关键注意事项

  • 体素间距一定要准确:CT图像的元数据里包含体素的实际物理尺寸(比如0.5mm×0.5mm×1mm),必须设置正确的spacing,否则导出的STL模型比例会完全错误。
  • 网格优化:如果导出的模型有破面或冗余结构,可以增加VTK平滑迭代次数,或使用PyVista的surface.clean()方法进一步优化。
  • 二值数据准确性:确保你的数组确实只有0和255,没有中间值,否则等值面提取会出现错误。

内容的提问来源于stack exchange,提问作者Mael Abgrall

火山引擎 最新活动