VTK 的可视化方法:等值面

VTK 的可视化方法:等值面

  • VTK 的可视化方法:等值面
    • VTK 中的数据表达
    • VTK 等值面提取类
    • 实例1:模型数据的等值面提取
    • 空间函数数据的等值面提取
    • 参考

VTK 的可视化方法:等值面

等值面是指一组具有相同标量值的点所构成的表面。

等值面(线)提取是一种常用的可视化技术,常应用于医学、地质、气象等领域。例如,在医学图像处理中,由于CT、MRI等图像分辨率越来越高,虽然体绘制技术可以清晰地对数据内部结构进行可视化,但是其计算量和效率却制约了其使用。此时可通过等值面提取技术,仅提取感兴趣的一个或者几个组织轮廓,并生成网格模型以供后续的处理和研究。

例子:

在这里插入图片描述

VTK 中的数据表达

  • Image Data:最基本的网格数据,存储复杂度是 O(1)。
  • Rectilinear Grid:放宽网格间距的限制,网格间距存储在 dx 和 dy 数组中,存储复杂度是 O(m+n)。

在这里插入图片描述

  • Structured Grid:放宽行列之间正交关系的约束,需要每个网格的 [px, py] 坐标,存储复杂度为 O(mn)。
  • Polygonal Data:网格拓扑结构的约束也不存在了,这时网格可以是离散的,需要更高的存储复杂度。

在这里插入图片描述

VTK 等值面提取类

根据数据类型的不同,VTK中提供了多个等值面提取类,其类图如图所示:

在这里插入图片描述

VTK中的等值面提取算法多基于MarchingCube算法来实现。MarchingCube是经典的移动立方体等值面提取算法。该算法是由W.E.Lorenson和H.E.Cline在1987年提出的。由于这一方法原理简单,易于实现,目前已经得到了较为广泛的应用,称为三维数据等值面生成的经典算法。

等值面提取类根据数据类型的不同而有所侧重:

  • vtkContourFilter:一个更加通用的等值面提取类,其可以接受任意的数据类型生成等值线或等值面。

  • vtkMarchingContourFilter:可以接受任何类型的数据,其内部根据数据不同生成不同的算法对象实现等值面/线的提取,具有较高的效率。

    • vtkDiscreteMarchingCubes:继承自vtkMarchingCubes,主要针对Label图像,比如利用图像分割算法对医学图像进行分割后得到含有不同Label值得数据,每个Label对应一个组织,如果想要得到其中一个或者几个组织的模型,则可以考虑使用该类。
  • vtkMarchingCubes:主要针对规则体数据生成等值面。

  • vtkImageMarchingCubes:主要处理三维图像数据。

  • vtkMarchingSquares:针对二维规则网格数据生成等值线。

实例1:模型数据的等值面提取

#include "VTKContour.h"

#include <vtkConeSource.h>
#include <vtkSTLReader.h>
#include <vtkMultiBlockPLOT3DReader.h>
#include <vtkDataSet.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkDataArray.h>
#include <vtkPointData.h>
#include <vtkShrinkPolyData.h>
#include <vtkStructuredGridGeometryFilter.h>
#include <vtkStructuredGridOutlineFilter.h>
#include <vtkContourFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>

VTKContour::VTKContour(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

	_pVTKWidget = new QVTKOpenGLNativeWidget();
	this->setCentralWidget(_pVTKWidget);
	// this->showMaximized();

	// 1. generate data
	// vtkSmartPointer<vtkConeSource> cone = vtkSmartPointer<vtkConeSource>::New();
	// or, read data
	// vtkMultiBlockPLOT3DReader 是一个读取器对象,用于读取 PLOT3D 格式的文件并在输出时生成结构化网格
	vtkSmartPointer<vtkMultiBlockPLOT3DReader> plot3dReader = vtkSmartPointer<vtkMultiBlockPLOT3DReader>::New();
	plot3dReader->SetXYZFileName("combxyz.bin");
	plot3dReader->SetQFileName("combq.bin");
	plot3dReader->SetScalarFunctionNumber(100);
	plot3dReader->SetVectorFunctionNumber(202);
	qDebug() << plot3dReader->GetOutput()->GetNumberOfBlocks(); // 0
	// 反向更新管线
	plot3dReader->Update();
	qDebug() << plot3dReader->GetOutput()->GetNumberOfBlocks(); // 1
	vtkDataSet* plot3dOutput = (vtkDataSet*)(plot3dReader->GetOutput()->GetBlock(0));
	// 获取标量数据
	vtkDataArray* scalars = plot3dOutput->GetPointData()->GetScalars();
	double* range = scalars->GetRange();
	qDebug() << range[0] << ":" << range[1];

	// 2. filter
	// 产生结构化栅格边界的一个线轮廓
	vtkSmartPointer<vtkStructuredGridOutlineFilter> outline = vtkSmartPointer<vtkStructuredGridOutlineFilter>::New();
	outline->SetInputData(plot3dOutput);
	// 等值面提取
	vtkSmartPointer<vtkContourFilter> contour = vtkSmartPointer<vtkContourFilter>::New();
	contour->SetInputData(plot3dOutput);
	// 在 range[0] 到 range[1] 的范围内提取 5 个等值面
	contour->GenerateValues(5, range[0], range[1]);

	// 3. mapper
	vtkSmartPointer<vtkPolyDataMapper> outlineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	vtkSmartPointer<vtkPolyDataMapper> contourMapper = vtkSmartPointer<vtkPolyDataMapper>::New();

	// 4. actor
	vtkSmartPointer<vtkActor> outlineActor = vtkSmartPointer<vtkActor>::New();
	vtkSmartPointer<vtkActor> contourActor = vtkSmartPointer<vtkActor>::New();

	// 5. renderer
	vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
	renderer->SetBackground(0.3, 0.6, 0.3); // Background Color: Green

	// 6. connect
	outlineMapper->SetInputConnection(outline->GetOutputPort());
	contourMapper->SetInputConnection(contour->GetOutputPort());
	outlineActor->SetMapper(outlineMapper);
	contourActor->SetMapper(contourMapper);
	renderer->AddActor(outlineActor);
	renderer->AddActor(contourActor);

	this->_pVTKWidget->renderWindow()->AddRenderer(renderer);
	this->_pVTKWidget->renderWindow()->Render();
}

VTKContour::~VTKContour()
{}

本程序首先获得了 plot3dOutput 的标量数据,从中得到了数据范围 range,使用 vtkContourFilter 等值面提取类,通过 contour->GenerateValues(5, range[0], range[1]) 提取了在 range[0] 到 range[1] 的范围内提取 5 个等值面。

运行结果:

在这里插入图片描述

空间函数数据的等值面提取

在本实例中,我们将用到vtkQuadric、vtkSampleFunction、vtkContourFilter三个类,分别是二次曲面函数、函数曲面抽样和等高滤波。

vtkQuadric负责二次曲面基本参数的设置,vtkSampleFunction则是对二次曲面进行等间隔逐点采样,在本例中采样点数为303030。vtkContourFilter负责将采集到空间点,转成vtkPolyData型对象。

#include "VTKContour.h"

#include <vtkConeSource.h>
#include <vtkSTLReader.h>
#include <vtkMultiBlockPLOT3DReader.h>
#include <vtkDataSet.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkDataArray.h>
#include <vtkPointData.h>
#include <vtkShrinkPolyData.h>
#include <vtkStructuredGridGeometryFilter.h>
#include <vtkStructuredGridOutlineFilter.h>
#include <vtkContourFilter.h>
#include <vtkQuadric.h>
#include <vtkSampleFunction.h>
#include <vtkLookupTable.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>

VTKContour::VTKContour(QWidget* parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	_pVTKWidget = new QVTKOpenGLNativeWidget();
	this->setCentralWidget(_pVTKWidget);
	// this->showMaximized();

	// 1. generate data
	// 二次曲面
	vtkSmartPointer<vtkQuadric> quadric = vtkSmartPointer<vtkQuadric>::New();
	quadric->SetCoefficients(0.5, 1, 0.2, 0, 0.1, 0, 0, 0.2, 0, 0);
	// 对二次曲面进行等间隔逐点采样
	vtkSmartPointer<vtkSampleFunction> sample = vtkSmartPointer<vtkSampleFunction>::New();
	// 设置采样分辨率为 30*30*30
	sample->SetSampleDimensions(30, 30, 30);
	sample->SetImplicitFunction(quadric);

	// 2. filter
	// 等值面提取,将采集到的空间点,转成 vtkPolyData 型对象
	vtkSmartPointer<vtkContourFilter> contour = vtkSmartPointer<vtkContourFilter>::New();
	contour->SetInputConnection(sample->GetOutputPort());
	// 在 [0, 1.2] 的范围内提取 5 个等值面
	contour->GenerateValues(5, 0, 1.2);

	// 3. mapper
	vtkSmartPointer<vtkPolyDataMapper> contourMapper = vtkSmartPointer<vtkPolyDataMapper>::New();

	// 4. actor
	vtkSmartPointer<vtkActor> contourActor = vtkSmartPointer<vtkActor>::New();

	// 5. renderer
	vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
	renderer->SetBackground(0.3, 0.6, 0.3); // Background Color: Green

	// 6. connect
	contourMapper->SetInputConnection(contour->GetOutputPort());
	contourActor->SetMapper(contourMapper);
	renderer->AddActor(contourActor);

	this->_pVTKWidget->renderWindow()->AddRenderer(renderer);
	this->_pVTKWidget->renderWindow()->Render();
}

VTKContour::~VTKContour()
{}

运行结果:

在这里插入图片描述

参考

  1. https://www.bilibili.com/video/BV11K411C7j9
  2. https://blog.csdn.net/m0_45306991/article/details/124710932
  3. https://www.cnblogs.com/phoenixdsg/p/6193904.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/587969.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

54.HarmonyOS鸿蒙系统 App(ArkTS)tcp socket套接字网络连接

54.HarmonyOS鸿蒙系统 App(ArkTS)tcp socket套接字网络连接 import socket from ohos.net.socket; import process from ohos.process; import wifiManager from ohos.wifiManager;import common from ohos.app.ability.common;let tcp socket.constructTCPSocketInstance();…

接收区块链的CCF会议--APSEC 2024 截止7.13 附录用率

会议名称&#xff1a;APSEC&#xff08;Asia-Pacific Software Engineering Conference&#xff09; CCF等级&#xff1a;CCF C类学术会议 类别&#xff1a;软件工程/系统软件/程序设计语言 录用率&#xff1a;2023年&#xff0c;90 submissions were recommended for accep…

智能指针解决多线程访问共享对象的线程安全问题

以下代码&#xff0c;在对象A被析构后&#xff0c;去访问A的成员对象&#xff0c;显然是不合理的。 class A { public:A() { cout << "A()" << endl; }~A() { cout << "~A()" << endl; }void testA() { cout << "非常…

OPA657运算放大器调研

运放是一种直流耦合&#xff0c;差模&#xff08;差动模式&#xff09;输入、通常为单端输出&#xff08;Differential-in, single-ended output&#xff09; [1] 的高增益&#xff08;gain&#xff09;电压放大器。运算放大器能产生一个比输入端电势差大数十万倍的输出电势&am…

Microsoft.NET 框架程序设计 —— 共享程序集

文件版本是一个很难解决的问题。实际上,如果仅仅在一个文件中将其某一位从0改变到1、或者从1改变到0,我们便不能绝对保证使用原来文件的代码和它使用新版文件时的行为一样。这是因为许多应用程序都会有意或者无意地引入bug。如果一个文件的后续版本修复了一个bug,应用程序便…

缓存分享(1)——Guava Cache原理及最佳实践

Guava Cache原理及最佳实践 1. Guava Cache是什么1.1 简介1.2 核心功能1.3 适用场景 2. Guava Cache的使用2.1 创建LoadingCache缓存2.2 创建CallableCache缓存 缓存的种类有很多&#xff0c;需要根据不同的应用场景来选择不同的cache&#xff0c;比如分布式缓存如redis、memca…

图床搭建GitHub+PicGo+jsdelivr(CDN)+Typora(内附加速工具)

目录 安装PicGo GitHub配置与加速器 配置PicGo 使用typroa 安装PicGo PicGo是一个用于上传图片的客户端&#xff0c;支持拖拽上传、剪贴板上传&#xff0c;功能十分方便。 下载地址&#xff1a; https://github.com/Molunerfinn/PicGo/releases 个人网盘自取版本2.4.0…

2024五一杯数学建模竞赛A题完整成品论文和代码分析:建立钢板切割的工艺路径动态规划、贪心与分层优化模型

2024五一杯数学建模竞赛A题&#xff1a;建立钢板切割的工艺路径动态规划、贪心与分层优化模型 2024五一数学建模A题完整代码和成品论文获取↓↓↓↓↓ https://www.yuque.com/u42168770/qv6z0d/gyoz9ou5upvkv6nx?singleDoc# 本文文章较长&#xff0c;建议先目录。经过不懈的…

IoTDB 入门教程③——基于Linux系统快速安装启动和上手

文章目录 一、前文二、下载三、解压四、上传五、启动六、执行七、停止八、参考 一、前文 IoTDB入门教程——导读 二、下载 下载二进制可运行程序&#xff1a;https://dlcdn.apache.org/iotdb/1.3.1/apache-iotdb-1.3.1-all-bin.zip 历史版本下载&#xff1a;https://archive.…

企业文化如何写??

编写企业文化时&#xff0c;要确保内容既能够体现公司的核心价值观、愿景和使命&#xff0c;又能够激发员工的归属感和工作热情。以下是一些关于如何编写企业文化的建议&#xff1a; 一、明确企业文化的重要性 企业文化是一个组织的灵魂&#xff0c;它影响着员工的工作态度、…

8、ftp使用教程

ftp使用教程 1、FTP概述&#xff1a;2、ftp主动模式和被动模式3、配置说明4、多用户配置5、异常6、ftp命令附录 1、FTP概述&#xff1a; ​ FTP是文件传输协议&#xff08;File Transfer Protocal&#xff09;的简写&#xff0c;主要完成与远程计算机的文件传输。 FTP采用客户…

【树——数据结构】

文章目录 1.基本概念2.基本术语1.结点之间的关系描述2.结点&#xff0c;树的属性描述3.有序树&#xff0c;无序树4.森林 3.树的性质考点1考点2考点3考点4 4.树的存储结构5.树和森林的遍历 1.基本概念 结点&#xff0c;根节点&#xff0c;分支结点&#xff0c;叶子结点&#xf…

【Mac】Axure RP 9(交互原型设计软件)安装教程

软件介绍 Axure RP 9是一款强大的原型设计工具&#xff0c;广泛用于用户界面和交互设计。它提供了丰富的功能和工具&#xff0c;能够帮助设计师创建高保真的交互原型&#xff0c;用于展示和测试软件应用或网站的功能和流程。以下是Axure RP 9的主要特点和功能&#xff1a; 交…

(1)探索 SpringAI - 基本概述

人工智能简介 A system is ability to correctly interpret external data, to learn from such data, and to use those learnings to achieve specific goals and tasks through flexible adaptation. 翻译&#xff1a;系统正确解释外部数据的能力&#xff0c;从这些数据中学…

Unity MeshRenderer 入门

概述 在项目制作过程中&#xff0c;肯定缺少不了模型的使用&#xff0c;那就一定接触过MeshRenderer&#xff0c;也许还有你不理解的地方&#xff0c;接下来让我们来学习一下这部分的内容吧。 Mesh Filter&#xff08;网格过滤器&#xff09; Mesh:提供一个网格的参考&#xf…

H.265 与 H.264 的主要区别

H.265 与 H.264 的主要区别 H.265 与 H.264 的主要区别各模块技术差异汇总宏块划分帧内预测模式帧间预测模式去块滤波ALF自适应环路滤波采样点自适应偏移&#xff08;Sample Adaptive Offset&#xff09;滤波并行化设计TileEntropy sliceDependent SliceWPP&#xff08;Wavefro…

WORD排版常见问题与解决方案

前言 近期使用word软件进行论文排版工作&#xff0c;遇到了一些常见的问题&#xff0c;记录一下&#xff0c;避免遗忘。 基本配置 系统环境&#xff1a;win10/win11 word版本&#xff1a;Microsoft Office LTSC 专业增强版 2021 问题与解决方案 问题1&#xff1a;页眉显示内…

Java IO流(一)

1. IO流概述 1.1 什么是IO流 在计算机中&#xff0c;input/output&#xff08;I/O、i/o 或非正式的 io 或 IO&#xff09;是信息处理系统&#xff08;例如计算机&#xff09;与外界&#xff08;可能是人类或其他信息处理系统&#xff09;之间的通信。 输入是系统接收到的信号或…

c#Excel:2.写入Excel表 3.读取Excel表

--写入Excel表-- 该例首先从数据库aq中读取学生信息表staq(参考数据库章节)&#xff0c;然后将学生信息表中的数据写入Excel表格中 &#xff08;1&#xff09;在OfficeOperator项目的ExcelOperator类中定义索引器&#xff0c;用于获取Excel表格中的单元格&#xff0c;代码如下…

理解Linux文件系统

文章目录 一、引言二、Linux文件系统概述1、文件系统的结构2、文件系统目录树的逻辑结构 二、文件系统的特性1、super block&#xff1a;文件系统的超级块2、inode&#xff1a;文件系统的索引节点3、inode table4、block&#xff1a;文件系统的数据块5、块组描述符表&#xff0…