13. VTK采集点法向量标记、平面切割

2024-01-22 11:36

本文主要是介绍13. VTK采集点法向量标记、平面切割,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天依旧是在摸索医学图像可视化的一天呢。这个笔记主要介绍了VTK上做法向量标记以及做切割平面的方法。

1. 将多边形数据的采集点法向量标记成锥形符号

在读取和使用.stl文件过程中,我们经常要用到法向量。这个例子展示了我们应该如何计算多边形数据的法向量并用vtkGlyph3D绘制圆锥型状将其标记出来。

  1. 读取stl文件构建多边形数据集
  2. 计算多边形数据的点法向量
  3. 使用vtkMaskPoints类采样部分数据,保留输入数据中的点数据及其属性
  4. 构建vtkGlyph3D对象,绘制形状设置为圆锥,数据源为采样点数据
  5. 绘制法向量数据和符号数据
#include "vtkSmartPointer.h"
#include "vtkPolyDataReader.h"
#include "vtkPolyDataNormals.h"
#include "vtkPolyDataMapper.h"
#include "vtkMaskPoints.h"
#include "vtkConeSource.h"
#include "vtkGlyph3D.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSTLReader.h"
#include "vtkProperty.h"#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);int main()
{//读取模型文件vtkSmartPointer<vtkSTLReader> obj = vtkSmartPointer<vtkSTLReader>::New();obj->SetFileName("D:\\ct\\20201102113826651_3d\\pelvis.stl");// 计算模型每个面的法矢量,创建一个法向量对象vtkSmartPointer<vtkPolyDataNormals> normals = vtkSmartPointer<vtkPolyDataNormals>::New();//计算单元法向量时,要保持单元法向量一致才能得到合理的法向量。SetConsistency()可以自动调整单元点的顺序;SetAutoOrientNormals()可以自动调整法向量方向。//类vtkPolyDataNormals自动开启对锐边缘处理,如果检测到锐边缘,会将其分裂,使图形更加平滑,可通过SetSplitting()函数关闭该功能。//三维平面的法向量是指垂直该平面的向量。某点的法向量为垂直该点切平面的法向量。// 将多边形数据集作为法向量对象的数据输入normals->SetInputConnection(obj->GetOutputPort());// 指定锐边角度为30度normals->SetFeatureAngle(30);// 关闭单元法向量计算(单元法向量可以通过组成每个单元的任意两条边的叉乘向量归并化来表示)normals->SetComputeCellNormals(0);// 开启点法向量计算(点的法向量则是由使用该点的单元单元法向量的平均值表示)normals->SetComputePointNormals(1);// 开启正常方向的全局翻转normals->SetFlipNormals(1);// 如果检测到锐边缘,会将其分裂,使图形更加平滑normals->SetSplitting(1);vtkSmartPointer<vtkPolyDataMapper> objMapper = vtkSmartPointer<vtkPolyDataMapper>::New();objMapper->SetInputConnection(normals->GetOutputPort());//由于读入的模型数据比较大,点比较多,因此使用vtkMaskPoints类采样部分数据,该类保留输入数据中的点数据及其属性,并支持点数据的采样vtkSmartPointer<vtkMaskPoints> ptMask = vtkSmartPointer<vtkMaskPoints>::New();ptMask->SetInputConnection(normals->GetOutputPort());//创建符号——圆锥形vtkSmartPointer<vtkConeSource> cone = vtkSmartPointer<vtkConeSource>::New();cone->SetAngle(26.5651);cone->SetHeight(1);cone->SetRadius(0.5);cone->SetResolution(6);cone->SetCapping(1);vtkSmartPointer<vtkGlyph3D> glyph = vtkSmartPointer<vtkGlyph3D>::New();//设置被标识的点glyph->SetInputConnection(normals->GetOutputPort());//设置符号glyph->SetSourceConnection(cone->GetOutputPort());vtkSmartPointer<vtkPolyDataMapper> glyphMapper = vtkSmartPointer<vtkPolyDataMapper>::New();glyphMapper->SetInputConnection(glyph->GetOutputPort());vtkSmartPointer<vtkActor> glyphActor = vtkSmartPointer<vtkActor>::New();glyphActor->SetMapper(glyphMapper);glyphActor->GetProperty()->SetColor(1, 0, 0);vtkSmartPointer<vtkActor> normalActor = vtkSmartPointer<vtkActor>::New();normalActor->SetMapper(objMapper);// Setup render window, renderer, and interactorvtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();renderer->AddActor(normalActor);renderer->AddActor(glyphActor);vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();renderWindow->AddRenderer(renderer);vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();renderWindowInteractor->SetRenderWindow(renderWindow);renderWindow->Render();renderWindowInteractor->Start();return 0;
}
运行结果:

 

备注: 

这里要特别注意.stl文件的读取问题。我一开始的写法是:

	obj->SetFileName("D:\ct\20201102113826651_3d\femur.stl");

 

就会出现以下问题:


 需要将代码里的地址改为双斜杠,即可正常读取文件。

obj->SetFileName("D:\\ct\\20201102113826651_3d\\pelvis.stl");

2. VTK构建切割面

在VTK中,如果我们需要构建一个切割面,需要做的步骤有:

1. 指定切割面中心SetOrigin()及切割面的法向量SetNormal()。

2. 设定切割面的个数及位置SetValue()GenerateValue()。

3. 设置切割过滤器对象vtkCutter, 指定被切割的数据集,及切割面隐函数vtkPlane。

4. 计算数据集在指定点的位置的属性vtkProbeFilter,指定切割对象的数据集及被切割的数据集。

5. 绘制vtkProbeFilter对象计算后的数据集(绘制的是切割对象的轮廓)。

#include "vtkPlane.h"
#include "vtkSTLReader.h"
#include "vtkPlane.h"
#include "vtkPolyData.h"
#include "vtkProbeFilter.h"
#include "vtkDataSetMapper.h"
#include "vtkPointData.h"
#include "vtkSmartPointer.h"
#include "vtkCutter.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);int main()
{//读取模型文件,被切割的数据vtkSmartPointer<vtkSTLReader> obj = vtkSmartPointer<vtkSTLReader>::New();obj->SetFileName("D:\\ct\\20201102113826651_3d\\femur.stl");obj->Update();//创建切割平面vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();//设定剪切平面在被剪切的数据中心位置vtkSmartPointer<vtkPolyData> polyData = obj->GetOutput();plane->SetOrigin(polyData->GetCenter());plane->SetNormal(-0.287, 0, 0.9579);// Print the plane parametersstd::cout << "Plane Origin: " << plane->GetOrigin() << std::endl;std::cout << "Plane Normal: " << plane->GetNormal() << std::endl;//过滤器类,利用隐函数对数据进行剪切vtkSmartPointer<vtkCutter> planeCut = vtkSmartPointer<vtkCutter>::New();// 设置被裁剪的数据集planeCut->SetInputConnection(obj->GetOutputPort());//设定隐函数planeCut->SetCutFunction(plane);planeCut->SetValue(0, 50);planeCut->GenerateValues(10, 0, 500);//计算数据集在指定点的位置的属性vtkSmartPointer<vtkProbeFilter> probe = vtkSmartPointer<vtkProbeFilter>::New();//计算平面在数据集通过点的属性probe->SetInputConnection(planeCut->GetOutputPort());//被计算的数据集probe->SetSourceConnection(obj->GetOutputPort());vtkSmartPointer<vtkDataSetMapper> cutMapper = vtkSmartPointer<vtkDataSetMapper>::New();cutMapper->SetInputConnection(probe->GetOutputPort());//得到数据点集属性值的范围vtkSmartPointer<vtkPointData> pData = vtkSmartPointer<vtkPointData>::New();pData = polyData->GetPointData();//设定属性值范围//cutMapper->SetScalarRange(pData->GetScalars()->GetRange());cutMapper->ScalarVisibilityOn();vtkSmartPointer<vtkActor> cutActor = vtkSmartPointer<vtkActor>::New();cutActor->SetMapper(cutMapper);// 可视化vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();renderer->SetBackground(.0, .0, .0);vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();renderWindow->AddRenderer(renderer);vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();renderWindowInteractor->SetRenderWindow(renderWindow);renderer->AddActor(cutActor);renderWindow->Render();renderWindowInteractor->Start();return 0;
}

 

运行结果:

如果想修改切面数量或者其他属性,修改这几行的参数即可:

	planeCut->SetCutFunction(plane);planeCut->SetValue(0, 50);planeCut->GenerateValues(50, 0, 500);

运行后,

备注:

一开始我运行代码的时候,出来的总是一片黑乎乎的,就很头疼。改了很久,发现是管道没有及时更新。这里要特别注意的是:在VTK的某些版本中,可能需要手动更新管道。在渲染之前,我们可能需要调用Update方法来确保所有的过滤器和读取器都处理了数据。

果然我就加上了这一行,就可以正常出来结果了:

	vtkSmartPointer<vtkSTLReader> obj = vtkSmartPointer<vtkSTLReader>::New();obj->SetFileName("D:\\ct\\20201102113826651_3d\\femur.stl");obj->Update();// 更新!!!确保STL文件被读取

这篇关于13. VTK采集点法向量标记、平面切割的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/632826

相关文章

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

脏页的标记方式详解

脏页的标记方式 一、引言 在数据库系统中,脏页是指那些被修改过但还未写入磁盘的数据页。为了有效地管理这些脏页并确保数据的一致性,数据库需要对脏页进行标记。了解脏页的标记方式对于理解数据库的内部工作机制和优化性能至关重要。 二、脏页产生的过程 当数据库中的数据被修改时,这些修改首先会在内存中的缓冲池(Buffer Pool)中进行。例如,执行一条 UPDATE 语句修改了某一行数据,对应的缓

三色标记(Tri-color marking)

维基百科部分 原文 https://en.wikipedia.org/wiki/Tracing_garbage_collection#TRI-COLOR Because of these performance problems, most modern tracing garbage collectors implement some variant of the tri-color ma

Vector3 三维向量

Vector3 三维向量 Struct Representation of 3D vectors and points. 表示3D的向量和点。 This structure is used throughout Unity to pass 3D positions and directions around. It also contains functions for doin

Verybot之OpenCV应用一:安装与图像采集测试

在Verybot上安装OpenCV是很简单的,只需要执行:         sudo apt-get update         sudo apt-get install libopencv-dev         sudo apt-get install python-opencv         下面就对安装好的OpenCV进行一下测试,编写一个通过USB摄像头采

8. 自然语言处理中的深度学习:从词向量到BERT

引言 深度学习在自然语言处理(NLP)领域的应用极大地推动了语言理解和生成技术的发展。通过从词向量到预训练模型(如BERT)的演进,NLP技术在机器翻译、情感分析、问答系统等任务中取得了显著成果。本篇博文将探讨深度学习在NLP中的核心技术,包括词向量、序列模型(如RNN、LSTM),以及BERT等预训练模型的崛起及其实际应用。 1. 词向量的生成与应用 词向量(Word Embedding)

13 transition数组的动画使用

划重点 动画:transitiontransition-group :数组动画数组的 添加 / 删除 豆腐粉丝汤 清淡又健康 <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><me

用Python实现时间序列模型实战——Day 14: 向量自回归模型 (VAR) 与向量误差修正模型 (VECM)

一、学习内容 1. 向量自回归模型 (VAR) 的基本概念与应用 向量自回归模型 (VAR) 是多元时间序列分析中的一种模型,用于捕捉多个变量之间的相互依赖关系。与单变量自回归模型不同,VAR 模型将多个时间序列作为向量输入,同时对这些变量进行回归分析。 VAR 模型的一般形式为: 其中: ​ 是时间  的变量向量。 是常数向量。​ 是每个时间滞后的回归系数矩阵。​ 是误差项向量,假

【CTF Web】BUUCTF Upload-Labs-Linux Pass-13 Writeup(文件上传+PHP+文件包含漏洞+PNG图片马)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。 注意 1.每一关没有固定的通关方法,大家不要自限思维! 2.本项目提供的writeup只是起一个参考作用,希望大家可以分享出自己的通关思路