DiscreteMarchingCubes离散等值面提取算法

一:主要的知识点

1、说明

本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程------逐行解析官网所有Python示例-CSDN博客

2、知识点纪要

本段代码主要涉及的有①vtkImageData的基本信息及基本使用

二:代码及注释

python 复制代码
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonCore import vtkLookupTable, vtkMinimalStandardRandomSequence
from vtkmodules.vtkCommonDataModel import vtkImageData, vtkSphere
from vtkmodules.vtkFiltersGeneral import vtkDiscreteFlyingEdges3D, vtkDiscreteMarchingCubes
from vtkmodules.vtkImagingCore import vtkImageThreshold
from vtkmodules.vtkImagingHybrid import vtkSampleFunction
from vtkmodules.vtkImagingMath import vtkImageMathematics
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)
 
 
def main():
    n = 20
    radius = 8
 
    """
    这里只创建了一个空壳的vtkImageData,因为这里不需要直接设置范围
    在 VTK 里,vtkImageData 自己本身可以设置 extent(索引范围) 和 spacing(体素间距),然后你才能在它里面放数据
    但是在本示例代码中,sampler 已经 决定了采样范围和分辨率
    SetModelBounds(-50, 50, -50, 50, -50, 50) = 空间边界
    SetSampleDimensions(100, 100, 100) = 每个方向的体素数量
    
    当 sampler.Update() 时,它会 创建一个新的 vtkImageData,范围就是 [-50,50]³  
    也就是说,这里的 vtkImageData 是 sampler 输出的结果,范围由 sampler 决定
    """
    blob_image = vtkImageData()
 
    max_r = 50 - 2.0 * radius
    random_sequence = vtkMinimalStandardRandomSequence()
    random_sequence.SetSeed(5071)
    for i in range(0, n):
        sphere = vtkSphere()
        sphere.SetRadius(radius)
        x = random_sequence.GetRangeValue(-max_r, max_r)
        random_sequence.Next()
        y = random_sequence.GetRangeValue(-max_r, max_r)
        random_sequence.Next()
        z = random_sequence.GetRangeValue(-max_r, max_r)
        random_sequence.Next()
 
        sphere.SetCenter(int(x), int(y), int(z))
 
        """
        创建一个 采样器 (vtkSampleFunction)
        它的作用是:在给定的空间范围内,均匀采样某个 隐式函数 (implicit function),
        并把结果存成 vtkImageData(体素格子)
        """
        sample = vtkSampleFunction()
        sample.SetImplicitFunction(sphere)
        """
        指定采样结果的标量类型。
        这里设置为 float,表示每个体素的值是浮点数(而不是整型)。
        好处是可以表示连续的函数值,而不仅仅是 0/1
        """
        sample.SetOutputScalarTypeToFloat()
        """
        指定采样网格的分辨率。
        在 X、Y、Z 三个方向各采样 100 个点 → 得到 100万 个体素。
        分辨率越高,结果越精细,但内存和计算也更大
        """
        sample.SetSampleDimensions(100, 100, 100)
        """
        设置采样空间的边界框(bounding box)
        也就是说,它会在这个立方体范围内均匀布置采样点,然后对球体函数进行采样
        """
        sample.SetModelBounds(-50, 50, -50, 50, -50, 50)
 
        """
        整段代码的含义是
        如果某个体素值 ≤ radius² → 说明它在球体内 → 标记为 i+1
        如果 > radius² → 说明它在球体外 → 标记为 0
        """
        thres = vtkImageThreshold()
        thres.SetInputConnection(sample.GetOutputPort())
        """
        表示保留所有 距离平方 ≤ radius² 的体素,也就是在球体内的体素
        """
        thres.ThresholdByLower(radius * radius)
        thres.ReplaceInOn()
        thres.ReplaceOutOn()
        thres.SetInValue(i + 1)
        thres.SetOutValue(0)
        thres.Update()
 
        if i == 0:
            blob_image.DeepCopy(thres.GetOutput())
 
        # 图像的像素级处理
        max_value = vtkImageMathematics()
        max_value.SetInputData(0, blob_image)
        max_value.SetInputData(1, thres.GetOutput())
        """
        做"逐体素最大值"运算.也就是说,球体之间的标签会取最大值,避免覆盖
        """
        max_value.SetOperationToMax()
        """
        Modified
        强制标记这个 filter 已经被修改,确保在调用 Update() 时重新执行图像运算,而不是复用旧缓存
        """
        max_value.Modified()
        max_value.Update()
 
        blob_image.DeepCopy(max_value.GetOutput())
 
    discrete = vtkDiscreteFlyingEdges3D()
    discrete.SetInputData(blob_image)
    """
    GenerateValues  指定要生成的等值面范围
    GenerateValues(numContours, rangeStart, rangeEnd) 的含义是:
    在 [rangeStart, rangeEnd] 之间 平均分布 numContours 个等值面值
    """
    discrete.GenerateValues(n, 1, n)
 
    lut = vtkLookupTable()
    lut.SetNumberOfColors(n)
    lut.SetTableRange(0, n - 1)
    """
    指定查找表的标量映射是线性的(而不是对数)
    """
    lut.SetScaleToLinear()
    lut.Build()
    """
    SetTableValue  把第 0 号颜色设为 (R=0, G=0, B=0, A=1),也就是 黑色,不透明
    """
    lut.SetTableValue(0, 0, 0, 0, 1)
 
    random_sequence = vtkMinimalStandardRandomSequence()
    random_sequence.SetSeed(5071)
    for i in range(1, n):
        r = random_sequence.GetRangeValue(0.4, 1)
        random_sequence.Next()
        g = random_sequence.GetRangeValue(0.4, 1)
        random_sequence.Next()
        b = random_sequence.GetRangeValue(0.4, 1)
        random_sequence.Next()
        lut.SetTableValue(i, r, g, b, 1.0)
 
    mapper = vtkPolyDataMapper()
    mapper.SetInputConnection(discrete.GetOutputPort())
    mapper.SetLookupTable(lut)
    mapper.SetScalarRange(0, lut.GetNumberOfColors())
 
    # Create the RenderWindow, Renderer and both Actors
    #
    ren = vtkRenderer()
    ren_win = vtkRenderWindow()
    ren_win.AddRenderer(ren)
    ren_win.SetWindowName('DiscreteMarchingCubes')
 
    iren = vtkRenderWindowInteractor()
    iren.SetRenderWindow(ren_win)
 
    actor = vtkActor()
    actor.SetMapper(mapper)
 
    ren.AddActor(actor)
 
    colors = vtkNamedColors()
    ren.SetBackground(colors.GetColor3d('Burlywood'))
 
    ren_win.Render()
 
    iren.Start()
 
 
if __name__ == '__main__':
    main()
相关推荐
biter down4 小时前
从 0 到 1 搭建 Python 接口自动化测试框架(博客系统实战)
开发语言·python
肖永威6 小时前
Python多业务并行计算框架插件化演进:从硬编码到动态注册
python·插件化·并行计算·动态注册
yz_aiks6 小时前
Linux Jar包配置Systemd自启动实战:从排查到配置全流程
linux·python·jar·自启动·systemd
不知名的老吴6 小时前
线程的生命周期之线程“插队“
java·开发语言·python
xsc6996757 小时前
从零搭建大模型与智能体平台 - 完整技术详解
python
无风听海8 小时前
多租户系统中的 OIDC:Discovery 端点与联合登录的深度实践
后端·python·flask
charlie1145141919 小时前
通用GUI编程技术——图形渲染实战(四十八)——Owner-Draw控件:让标准控件焕然一新
图形渲染
CTA终结者9 小时前
期货量化主力换月程序怎么移仓:天勤 underlying_symbol 与任务切换
python·区块链
马士兵教育9 小时前
Java还有前景吗?Java+AI大模型学习路线及项目?
java·人工智能·python·学习·机器学习
KaMeidebaby10 小时前
卡梅德生物技术快报|纯化重组蛋白实操详解
人工智能·python·tcp/ip·算法·机器学习