MarchingCases marchingcubes算法15种情况的展示

一:主要的知识点

1、说明

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

2、知识点纪要

本段代码主要涉及的有①MarchingCubes等值面重建的原理展示

二:代码及注释

python 复制代码
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonCore import vtkFloatArray, vtkIdList, vtkPoints
from vtkmodules.vtkCommonDataModel import vtkUnstructuredGrid, VTK_HEXAHEDRON
from vtkmodules.vtkCommonTransforms import vtkTransform
from vtkmodules.vtkFiltersCore import vtkContourFilter, vtkGlyph3D, vtkThresholdPoints, vtkTubeFilter
from vtkmodules.vtkFiltersCore import vtkExtractEdges
from vtkmodules.vtkFiltersGeneral import vtkShrinkPolyData, vtkTransformPolyDataFilter
from vtkmodules.vtkFiltersSources import (
    vtkCubeSource,
    vtkSphereSource
)
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)
from vtkmodules.vtkRenderingFreeType import vtkVectorText
 
Scalars = vtkFloatArray()
 
 
def main():
    cases = [case0, case1, case2, case3, case4, case5, case6, case7, case8, case9, case10, case11, case12, case13,
             case14]
    colors = vtkNamedColors()
    rotation = 0
 
    renderers = list()
    gridSize = ((len(cases) + 3) // 4) * 4
 
    renWin = vtkRenderWindow()
    renWin.SetSize(640, 480)
    iren = vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)
 
    for i in range(0, 16):
        renderer = vtkRenderer()
        renderers.append(renderer)
        renderers[i].SetBackground(colors.GetColor3d("slate_grey"))
        renWin.AddRenderer(renderer)
 
    for i in range(0, len(cases)):
        Scalars = vtkFloatArray()
        Scalars.InsertNextValue(1.0)
        Scalars.InsertNextValue(0.0)
        Scalars.InsertNextValue(0.0)
        Scalars.InsertNextValue(1.0)
        Scalars.InsertNextValue(0.0)
        Scalars.InsertNextValue(0.0)
        Scalars.InsertNextValue(0.0)
        Scalars.InsertNextValue(0.0)
 
        Points = vtkPoints()
        Points.InsertNextPoint(0, 0, 0)
        Points.InsertNextPoint(1, 0, 0)
        Points.InsertNextPoint(1, 1, 0)
        Points.InsertNextPoint(0, 1, 0)
        Points.InsertNextPoint(0, 0, 1)
        Points.InsertNextPoint(1, 0, 1)
        Points.InsertNextPoint(1, 1, 1)
        Points.InsertNextPoint(0, 1, 1)
 
        Ids = vtkIdList()
        Ids.InsertNextId(0)
        Ids.InsertNextId(1)
        Ids.InsertNextId(2)
        Ids.InsertNextId(3)
        Ids.InsertNextId(4)
        Ids.InsertNextId(5)
        Ids.InsertNextId(6)
        Ids.InsertNextId(7)
 
        Grid = vtkUnstructuredGrid()
        """
        第一个参数:插入10个单元格
        第二个参数:每个单元格插入10个点
        但是在这个按理中,每个立方体只有一个单元格 10>1
        每个单元格只有8个点, 10 > 8
        示例代码很明显是分配空间> 所需空间
        """
        Grid.Allocate(10, 10)
        Grid.InsertNextCell(VTK_HEXAHEDRON, Ids)
        Grid.SetPoints(Points)
        Grid.GetPointData().SetScalars(Scalars)
 
        marching = vtkContourFilter()
        marching.SetInputData(Grid)
        marching.SetValue(0, 0.5)
        marching.Update()
 
        # 提取经由marching找到的等值面三角网格面的边缘
        triangleEdges = vtkExtractEdges()
        triangleEdges.SetInputConnection(marching.GetOutputPort())
 
        # 将提取的边缘变粗,方便可视化
        triangleEdgeTubes = vtkTubeFilter()
        triangleEdgeTubes.SetInputConnection(triangleEdges.GetOutputPort())
        triangleEdgeTubes.SetRadius(0.005)
        triangleEdgeTubes.SetNumberOfSides(6)
        triangleEdgeTubes.UseDefaultNormalOn()  # 使用默认法线
        triangleEdgeTubes.SetDefaultNormal(.577, .577, .577)
 
        triangleEdgeMapper = vtkPolyDataMapper()
        triangleEdgeMapper.SetInputConnection(triangleEdgeTubes.GetOutputPort())
        triangleEdgeMapper.ScalarVisibilityOff()
 
        triangleEdgeActor = vtkActor()
        triangleEdgeActor.SetMapper(triangleEdgeMapper)
        triangleEdgeActor.GetProperty().SetDiffuseColor(colors.GetColor3d("lamp_black"))
        triangleEdgeActor.GetProperty().SetSpecular(.4)  # 设置镜面反射
        triangleEdgeActor.GetProperty().SetSpecularPower(10)  # 设置镜面强度
 
        aShrikner = vtkShrinkPolyData()
        aShrikner.SetInputConnection(marching.GetOutputPort())
        aShrikner.SetShrinkFactor(1.0)
 
        aMapper = vtkPolyDataMapper()
        aMapper.ScalarVisibilityOff()
        aMapper.SetInputConnection(aShrikner.GetOutputPort())
 
        Triangles = vtkActor()
        Triangles.SetMapper(aMapper)
        Triangles.GetProperty().SetDiffuseColor(colors.GetColor3d('banana'))
        Triangles.GetProperty().SetOpacity(.6)
 
        # 整体的立方体的构建
        CubeModel = vtkCubeSource()
        CubeModel.SetCenter(.5, .5, .5)
 
        Edges = vtkExtractEdges()
        Edges.SetInputConnection(CubeModel.GetOutputPort())
 
        Tubes = vtkTubeFilter()
        Tubes.SetInputConnection(Edges.GetOutputPort())
        Tubes.SetRadius(.01)
        Tubes.SetNumberOfSides(6)
        Tubes.UseDefaultNormalOn()
        Tubes.SetDefaultNormal(.577, .577, .577)
 
        TubeMapper = vtkPolyDataMapper()
        TubeMapper.SetInputConnection(Tubes.GetOutputPort())
        CubeEdges = vtkActor()
        CubeEdges.SetMapper(TubeMapper)
        CubeEdges.GetProperty().SetDiffuseColor(
            colors.GetColor3d('khaki'))
        CubeEdges.GetProperty().SetSpecular(.4)
        CubeEdges.GetProperty().SetSpecularPower(10)
 
        # 新建球体,用来表示marching cubes哪里是1,哪里是0
        sphere = vtkSphereSource()
        sphere.SetRadius(0.04)
        sphere.SetPhiResolution(20)
        sphere.SetThetaResolution(20)
 
        # 移除掉grid中点的scalar
        ThresholdIn = vtkThresholdPoints()
        ThresholdIn.SetInputData(Grid)
        ThresholdIn.ThresholdByUpper(.5) # 只保留标量值小于或等于 0.5 的所有点
 
        Vertices = vtkGlyph3D()
        Vertices.SetInputConnection(ThresholdIn.GetOutputPort())
        Vertices.SetSourceConnection(sphere.GetOutputPort())
 
        SphereMapper = vtkPolyDataMapper()
        SphereMapper.SetInputConnection(Vertices.GetOutputPort())
        SphereMapper.ScalarVisibilityOff()
 
        CubeVertices = vtkActor()
        CubeVertices.SetMapper(SphereMapper)
        CubeVertices.GetProperty().SetDiffuseColor(
            colors.GetColor3d('tomato'))
 
        caseLabel = vtkVectorText()
 
        aLabelTransform = vtkTransform()
        aLabelTransform.Identity()
        aLabelTransform.Translate(-0.2, 0, 1.25)
        aLabelTransform.Scale(.05, .05, .05)
 
        # 将label这个数据移动到新的位置
        labelTransform = vtkTransformPolyDataFilter()
        labelTransform.SetTransform(aLabelTransform)
        labelTransform.SetInputConnection(caseLabel.GetOutputPort())
 
        labelMapper = vtkPolyDataMapper()
        labelMapper.SetInputConnection(labelTransform.GetOutputPort())
 
        labelActor = vtkActor()
        labelActor.SetMapper(labelMapper)
 
        # 设置一个基座,用来放置grid
        baseModel = vtkCubeSource()
        baseModel.SetXLength(1.5)
        baseModel.SetYLength(0.01)
        baseModel.SetZLength(1.5)
 
        baseMapper = vtkPolyDataMapper()
        baseMapper.SetInputConnection(baseModel.GetOutputPort())
 
        base = vtkActor()
        base.SetMapper(baseMapper)
        base.SetPosition(.5, -0.09, .5)
 
        """
        在这里,完成对于Scalars标量值的更新
        """
        cases[i](Scalars, caseLabel, 1, 0)
        """
        Grid对象进行数据更新
        为什么Scalars这个对象的更新,能够影响到已经构建好了的Grid里面的标量的值??
        Grid.GetPointData().SetScalars(Scalars) 这一行没有复制数据,只是建立起了一个引用
        SetScalars() 的作用:建立联系,而非复制数据
        你可以把 Scalars 想象成一个装满水的水桶,而 Grid 就像一个需要水的洒水器。
        Grid.GetPointData().SetScalars(Scalars) 这句话的作用是:
        "把洒水器的进水管,接到这个水桶上。"
        这行代码执行之后,Grid(洒水器)就知道去哪里找它的水源(Scalars)。它本身没有自己的水,它只是引用着 Scalars 这个水桶里的数据。
        当你循环中调用 caseX(Scalars, ...) 函数时,你实际上是在:
        "直接往这个水桶里倒新水。"
        因为 Grid 的进水管一直连接着同一个水桶,所以当你改变 Scalars 里数据的时候,Grid 立即就能"看到"这些变化。
        Grid.Modified() 的作用就是:
        "告诉洒水器:嘿,水桶里的水换了,记得重新检查一下!"
        如果没有这句通知,洒水器可能懒得去检查,继续用它之前的水。有了这句通知,它就会去检查水桶,发现水变了,然后把新数据传递给下游的过滤器(vtkContourFilter)
        """
        Grid.Modified()
 
        renderers[i].AddActor(triangleEdgeActor)
        renderers[i].AddActor(base)
        renderers[i].AddActor(labelActor)
        renderers[i].AddActor(CubeEdges)
        renderers[i].AddActor(CubeVertices)
        renderers[i].AddActor(Triangles)
 
        renderers[i].GetActiveCamera().Azimuth(30)
 
        renderers[i].GetActiveCamera().Elevation(20)
        renderers[i].ResetCamera()
        renderers[i].ResetCameraClippingRange()
 
        """
        原本的示例代码是这样写的
        if i > 0:
            renderers[i].SetActiveCamera(renderers[0].GetActiveCamera())
        这行代码的意思是,所有的render都使用索引为0的render的那个相机
        这就意味着,窗口的所有render在鼠标进行操作时,因为是一个相机,所有的render都会一起变化
        """
 
    rendererSize = 300
    xGridDimensions = 4
    yGridDimensions = (len(cases) - 1) // 4 + 1
    print('Grid dimensions, (x, y): ({:d}, {:d})'.format(xGridDimensions, yGridDimensions))
    renWin.SetSize(
        rendererSize * xGridDimensions, rendererSize * yGridDimensions)
    renWin.SetWindowName('MarchingCases')
 
    """
    vtk的惰性执行,哪怕前面已经将render塞入到renderwindow中,这里再进行更改也是可以的
    """
    for row in range(0, yGridDimensions):
        for col in range(0, xGridDimensions):
            index = row * xGridDimensions + col
 
            # (xmin, ymin, xmax, ymax)
            viewport = [
                float(col) / xGridDimensions,
                float(yGridDimensions - (row + 1)) / yGridDimensions,
                float(col + 1) / xGridDimensions,
                float(yGridDimensions - row) / yGridDimensions]
 
            renderers[index].SetViewport(viewport)
 
 
 
    iren.Initialize()
    renWin.Render()
    iren.Start()
 
 
def case0(scalars: vtkFloatArray,
          caseLabel: vtkVectorText,
          IN: float,
          OUT: float):
    # SetValue和InsertValue这两种写法都可以
    scalars.SetValue(0, OUT)
    scalars.SetValue(1, OUT)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, OUT)
    scalars.InsertValue(4, OUT)
    scalars.InsertValue(5, OUT)
    scalars.InsertValue(6, OUT)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 0 - 00000000')
    else:
        caseLabel.SetText('Case 0c - 11111111')
 
 
def case1(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, IN)
    scalars.InsertValue(1, OUT)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, OUT)
    scalars.InsertValue(4, OUT)
    scalars.InsertValue(5, OUT)
    scalars.InsertValue(6, OUT)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 1 - 00000001')
    else:
        caseLabel.SetText('Case 1c - 11111110')
 
 
def case2(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, IN)
    scalars.InsertValue(1, IN)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, OUT)
    scalars.InsertValue(4, OUT)
    scalars.InsertValue(5, OUT)
    scalars.InsertValue(6, OUT)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 2 - 00000011')
    else:
        caseLabel.SetText('Case 2c - 11111100')
 
 
def case3(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, IN)
    scalars.InsertValue(1, OUT)
    scalars.InsertValue(2, IN)
    scalars.InsertValue(3, OUT)
    scalars.InsertValue(4, OUT)
    scalars.InsertValue(5, OUT)
    scalars.InsertValue(6, OUT)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 3 - 00000101')
    else:
        caseLabel.SetText('Case 3c - 11111010')
 
 
def case4(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, IN)
    scalars.InsertValue(1, OUT)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, OUT)
    scalars.InsertValue(4, OUT)
    scalars.InsertValue(5, OUT)
    scalars.InsertValue(6, IN)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 4 - 01000001')
    else:
        caseLabel.SetText('Case 4c - 10111110')
 
 
def case5(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, OUT)
    scalars.InsertValue(1, IN)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, OUT)
    scalars.InsertValue(4, IN)
    scalars.InsertValue(5, IN)
    scalars.InsertValue(6, OUT)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 5 - 00110010')
    else:
        caseLabel.SetText('Case 5c - 11001101')
 
 
def case6(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, OUT)
    scalars.InsertValue(1, IN)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, IN)
    scalars.InsertValue(4, IN)
    scalars.InsertValue(5, OUT)
    scalars.InsertValue(6, OUT)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 6 - 00011010')
    else:
        caseLabel.SetText('Case 6c - 11100101')
 
 
def case7(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, IN)
    scalars.InsertValue(1, IN)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, OUT)
    scalars.InsertValue(4, OUT)
    scalars.InsertValue(5, OUT)
    scalars.InsertValue(6, IN)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 7 - 01000011')
    else:
        caseLabel.SetText('Case 7c - 10111100')
 
 
def case8(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, IN)
    scalars.InsertValue(1, IN)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, OUT)
    scalars.InsertValue(4, IN)
    scalars.InsertValue(5, IN)
    scalars.InsertValue(6, OUT)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 8 - 00110011')
    else:
        caseLabel.SetText('Case 8c - 11001100')
 
 
def case9(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, OUT)
    scalars.InsertValue(1, IN)
    scalars.InsertValue(2, IN)
    scalars.InsertValue(3, IN)
    scalars.InsertValue(4, OUT)
    scalars.InsertValue(5, OUT)
    scalars.InsertValue(6, IN)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 9 - 01001110')
    else:
        caseLabel.SetText('Case 9c - 10110001')
 
 
def case10(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, IN)
    scalars.InsertValue(1, OUT)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, IN)
    scalars.InsertValue(4, OUT)
    scalars.InsertValue(5, IN)
    scalars.InsertValue(6, IN)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 10 - 01101001')
    else:
        caseLabel.SetText('Case 10c - 10010110')
 
 
def case11(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, IN)
    scalars.InsertValue(1, OUT)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, OUT)
    scalars.InsertValue(4, IN)
    scalars.InsertValue(5, IN)
    scalars.InsertValue(6, IN)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 11 - 01110001')
    else:
        caseLabel.SetText('Case 11c - 10001110')
 
 
def case12(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, OUT)
    scalars.InsertValue(1, IN)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, IN)
    scalars.InsertValue(4, IN)
    scalars.InsertValue(5, IN)
    scalars.InsertValue(6, OUT)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 12 - 00111010')
    else:
        caseLabel.SetText('Case 12c - 11000101')
 
 
def case13(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, OUT)
    scalars.InsertValue(1, IN)
    scalars.InsertValue(2, OUT)
    scalars.InsertValue(3, IN)
    scalars.InsertValue(4, IN)
    scalars.InsertValue(5, OUT)
    scalars.InsertValue(6, IN)
    scalars.InsertValue(7, OUT)
    if IN == 1:
        caseLabel.SetText('Case 13 - 01011010')
    else:
        caseLabel.SetText('Case 13c - 10100101')
 
 
def case14(scalars, caseLabel, IN, OUT):
    scalars.InsertValue(0, IN)
    scalars.InsertValue(1, OUT)
    scalars.InsertValue(2, IN)
    scalars.InsertValue(3, IN)
    scalars.InsertValue(4, OUT)
    scalars.InsertValue(5, IN)
    scalars.InsertValue(6, IN)
    scalars.InsertValue(7, IN)
    if IN == 1:
        caseLabel.SetText('Case 14 - 11101101')
    else:
        caseLabel.SetText('Case 14c - 00010010')
 
 
if __name__ == '__main__':
    main()
相关推荐
彼岸花开了吗5 小时前
构建AI智能体:五十二、反应式智能体:基于“感知-行动”,AI世界的条件反射
人工智能·python·agent
weixin_429690725 小时前
# 数字人系统开发:如何选择可靠的开源方案在人工智能和虚
人工智能·python·开源
艾上编程5 小时前
《Python实战小课:数据分析场景——解锁数据洞察之力》导读
python·数据挖掘·数据分析
Lyinj5 小时前
从一个编辑校验问题谈接口设计的边界
java·spring boot·python·学习
纪伊路上盛名在5 小时前
文献阅读自动化1-批量检索、更新文献
python·自动化·文献阅读·科研日常·流程化
梦白.5 小时前
Python字符串类型
linux·python
gf13211115 小时前
python_图片、字幕文本、音频一键组合
python·音视频·swift
查拉图斯特拉面条6 小时前
UI自动化断言完全指南:从基础到高级的断言表达式实战
python·自动化