news 2026/1/26 16:31:55

MarchingCases marchingcubes算法15种情况的展示

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MarchingCases marchingcubes算法15种情况的展示

一:主要的知识点

1、说明

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

2、知识点纪要

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


二:代码及注释

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()
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/24 18:01:13

Java IO 实战学习指南:从基础到进阶(附代码实操)

Java IO 实战学习指南:从基础到进阶(附代码实操) Java IO(输入/输出)是Java开发的核心基础,负责程序与外部设备(文件、网络、键盘等)的数据交互。很多初学者觉得IO类繁多、流概念抽象…

作者头像 李华
网站建设 2026/1/24 19:15:43

Docker命令合集详解

总结的相对全面且详细的 Docker 和 Docker Compose 命令合集。为了方便查阅,我将其分为 基础/镜像管理、容器操作、Docker Compose 编排 以及 常用参数详解 四个部分。第一部分:Docker 基础与镜像命令 (Images) 镜像(Image)是容器…

作者头像 李华
网站建设 2026/1/19 16:14:59

3分钟极速部署OpenMetadata元数据平台的完整指南

3分钟极速部署OpenMetadata元数据平台的完整指南 【免费下载链接】OpenMetadata 开放标准的元数据。一个发现、协作并确保数据正确的单一地点。 项目地址: https://gitcode.com/GitHub_Trending/op/OpenMetadata 一键启动配置,快速搭建企业级数据治理平台。本…

作者头像 李华
网站建设 2026/1/14 5:15:32

11、深入探索Bash脚本:自动完成与环境定制

深入探索Bash脚本:自动完成与环境定制 1. 为自定义应用编写Bash自动完成功能 当使用 complete -r 命令时,如果没有指定 command_name 作为参数,所有的自动完成规范都会被移除: $ complete -r $ completeBash-completion包并不为外部工具提供自动完成功能。若要为有…

作者头像 李华
网站建设 2026/1/24 4:02:47

中文医学基准测试题库数据集:28万条标准化JSON格式医师考试题目与临床案例分析,覆盖28个医学专业领域,用于医学AI模型训练、临床决策支持系统开发、医学知识问答系统构建、医学教育辅助工具优化

中文医学基准测试题库数据集:28万条标准化JSON格式医师考试题目与临床案例分析,覆盖28个医学专业领域,用于医学AI模型训练、临床决策支持系统开发、医学知识问答系统构建、医学教育辅助工具优化 引言与背景 在人工智能技术快速发展的今天&a…

作者头像 李华
网站建设 2026/1/25 5:11:38

终极指南:m3u8下载器命令行工具,实现全自动视频批量采集

终极指南:m3u8下载器命令行工具,实现全自动视频批量采集 【免费下载链接】m3u8-downloader m3u8 视频在线提取工具 流媒体下载 m3u8下载 桌面客户端 windows mac 项目地址: https://gitcode.com/gh_mirrors/m3u8/m3u8-downloader 还在为重复下载m…

作者头像 李华