VTK 数据处理:特征边提取

VTK 数据处理:特征边提取

  • VTK 数据处理:特征边提取
    • 原理
    • 实例 1:边界边提取
    • 实例 2:模型特征边提取
    • 实例 3:利用 vtkFeatureEdges 提取的边界补洞
    • 实例 4:利用 vtkFillHolesFilter 补洞

VTK 数据处理:特征边提取

原理

VTK 的特征边提取只针对 PolyData,属于拓扑操作。

可以提取出 4 种类型的边:

  1. 边界边:只被 1 个网格使用的边;
  2. 流形边:被 2 个网格使用的边;
  3. 非流形边:被 2 个以上网格使用的边,一般不会在 PolyData 中出现;
  4. 特征边:属于流形边的一种,当一条流形边关联的两个面片的夹角大于特征角的话,它就是特征边。

实例 1:边界边提取

本实例创建了一个 vtkDiskSource 对象 disk,通过 vtkFeatureEdges 类提取 disk 的边界边,并设置不提取流形边、非流形边和特征边,并显示边界边的颜色以作区分。

VTKBoundaryEdge.h:

#pragma once#include <QtWidgets/QMainWindow>
#include "ui_VTKFeatureEdge.h"#include <QVTKOpenGLNativeWidget.h>class VTKBoundaryEdge : public QMainWindow
{Q_OBJECTpublic:VTKBoundaryEdge(QWidget* parent = nullptr);~VTKBoundaryEdge();private:Ui::VTKFeatureEdgeClass ui;QVTKOpenGLNativeWidget* _pVTKWidget = nullptr;
};

VTKBoundaryEdge.cpp:

#include "VTKBoundaryEdge.h"#include <vtkDiskSource.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkPolyData.h>
#include <vtkFeatureEdges.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>VTKBoundaryEdge::VTKBoundaryEdge(QWidget* parent) : QMainWindow(parent)
{ui.setupUi(this);_pVTKWidget = new QVTKOpenGLNativeWidget();this->setCentralWidget(_pVTKWidget);vtkNew<vtkRenderer> renderer;this->_pVTKWidget->renderWindow()->AddRenderer(renderer);this->_pVTKWidget->renderWindow()->Render();vtkNew<vtkDiskSource> disk;disk->Update();vtkNew<vtkFeatureEdges> featureEdges;featureEdges->SetInputConnection(disk->GetOutputPort());featureEdges->BoundaryEdgesOn(); // 提取边界边设置打开featureEdges->ManifoldEdgesOff();featureEdges->NonManifoldEdgesOff();featureEdges->FeatureEdgesOff();featureEdges->ColoringOn(); // 显示颜色vtkNew<vtkPolyDataMapper> diskMapper;diskMapper->SetInputConnection(disk->GetOutputPort());vtkNew<vtkPolyDataMapper> edgeMapper;edgeMapper->SetInputConnection(featureEdges->GetOutputPort());vtkNew<vtkActor> diskActor;diskActor->SetMapper(diskMapper);vtkNew<vtkActor> edgeActor;edgeActor->SetMapper(edgeMapper);renderer->AddActor(diskActor);renderer->AddActor(edgeActor);
}VTKBoundaryEdge::~VTKBoundaryEdge()
{
}

运行结果:

在这里插入图片描述

实例 2:模型特征边提取

前面提到特征边的识别取决于两个面片的夹角,如下图所示,指针指着的角就是夹角,VTK 默认将该角大于 30 度的都视为特征边。可以看出,连续性不是很好的边都被视为特征边。

在这里插入图片描述

本实例使用 vtkBYUReader 读取了一个牛的模型,并用 vtkFeatureEdges 类提取了模型的特征边,并设置不提取流形边、非流形边和边界边,并显示特征边的颜色以作区分。

VTKFeatureEdge.h:

#pragma once#include <QtWidgets/QMainWindow>
#include "ui_VTKFeatureEdge.h"#include <QVTKOpenGLNativeWidget.h>class VTKFeatureEdge : public QMainWindow
{Q_OBJECTpublic:VTKFeatureEdge(QWidget* parent = nullptr);~VTKFeatureEdge();private:Ui::VTKFeatureEdgeClass ui;QVTKOpenGLNativeWidget* _pVTKWidget = nullptr;
};

VTKFeatureEdge.cpp:

#include "VTKFeatureEdge.h"#include <vtkBYUReader.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkPolyData.h>
#include <vtkFeatureEdges.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>VTKFeatureEdge::VTKFeatureEdge(QWidget* parent): QMainWindow(parent)
{ui.setupUi(this);_pVTKWidget = new QVTKOpenGLNativeWidget();this->setCentralWidget(_pVTKWidget);vtkNew<vtkRenderer> renderer;this->_pVTKWidget->renderWindow()->AddRenderer(renderer);this->_pVTKWidget->renderWindow()->Render();vtkNew<vtkBYUReader> reader;reader->SetFileName("cow.g");reader->Update();vtkNew<vtkFeatureEdges> featureEdges;featureEdges->SetInputConnection(reader->GetOutputPort());featureEdges->BoundaryEdgesOff();featureEdges->ManifoldEdgesOn(); // 提取特征边设置打开featureEdges->NonManifoldEdgesOff();featureEdges->FeatureEdgesOff();featureEdges->ColoringOn(); // 显示颜色vtkNew<vtkPolyDataMapper> cowMapper;cowMapper->SetInputConnection(reader->GetOutputPort());vtkNew<vtkPolyDataMapper> edgeMapper;edgeMapper->SetInputConnection(featureEdges->GetOutputPort());vtkNew<vtkActor> cowActor;cowActor->SetMapper(cowMapper);vtkNew<vtkActor> edgeActor;edgeActor->SetMapper(edgeMapper);renderer->AddActor(cowActor);renderer->AddActor(edgeActor);
}VTKFeatureEdge::~VTKFeatureEdge()
{}

实例 3:利用 vtkFeatureEdges 提取的边界补洞

建立一个 vtkPlane 类对象作为截面, 设置好 plane 的法向量。利用 vtkClipPolyData 类将模型作为输入,将 plane 设为 clipper 的截取函数。再用 vtkFeatureEdges 类提取截取后模型 clipper 的边界边。将边界边作为 vtkStripper 类对象 boundaryStrips 的输入,将 featureEdges 生成的三角片连接成三角带,再转换成多边形数据 boundaryPolyData。最后把 clipper、featureEdges、boundaryPolyData 全部显示出来。

#include "VTKFeatureEdge.h"#include <vtkBYUReader.h>
#include <vtkPlane.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkPolyData.h>
#include <vtkClipPolyData.h>
#include <vtkFeatureEdges.h>
#include <vtkStripper.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>VTKFeatureEdge::VTKFeatureEdge(QWidget* parent): QMainWindow(parent)
{ui.setupUi(this);_pVTKWidget = new QVTKOpenGLNativeWidget();this->setCentralWidget(_pVTKWidget);vtkNew<vtkRenderer> renderer;this->_pVTKWidget->renderWindow()->AddRenderer(renderer);this->_pVTKWidget->renderWindow()->Render();vtkNew<vtkBYUReader> reader;reader->SetFileName("cow.g");reader->Update();// 截面vtkNew<vtkPlane> plane;plane->SetOrigin(reader->GetOutput()->GetCenter());plane->SetNormal(1.0, -1.0, -1.0); // 设置截面的法向量// 截取模型vtkNew<vtkClipPolyData> clipper;clipper->SetInputData(reader->GetOutput());clipper->SetClipFunction(plane); // 将 plane 设为 clipper 的截取函数clipper->SetValue(0.0);vtkNew<vtkFeatureEdges> featureEdges;featureEdges->SetInputConnection(clipper->GetOutputPort());featureEdges->BoundaryEdgesOn();featureEdges->ManifoldEdgesOff(); // 提取特征边设置打开featureEdges->NonManifoldEdgesOff();featureEdges->FeatureEdgesOff();featureEdges->ColoringOn(); // 显示颜色// 建立三角带对象vtkNew<vtkStripper> boundaryStrips;boundaryStrips->SetInputConnection(featureEdges->GetOutputPort()); // 将 featureEdges 生成的三角片连接成三角带boundaryStrips->Update();vtkNew<vtkPolyData> boundaryPolyData;boundaryPolyData->SetPoints(boundaryStrips->GetOutput()->GetPoints());boundaryPolyData->SetPolys(boundaryStrips->GetOutput()->GetLines());vtkNew<vtkPolyDataMapper> clipperMapper;clipperMapper->SetInputConnection(clipper->GetOutputPort());vtkNew<vtkPolyDataMapper> edgeMapper;edgeMapper->SetInputConnection(featureEdges->GetOutputPort());vtkNew<vtkPolyDataMapper> boundaryMapper;boundaryMapper->SetInputData(boundaryPolyData);vtkNew<vtkActor> clipperActor;clipperActor->SetMapper(clipperMapper);vtkNew<vtkActor> edgeActor;edgeActor->SetMapper(edgeMapper);vtkNew<vtkActor> boundaryActor;boundaryActor->SetMapper(boundaryMapper);renderer->AddActor(clipperActor);renderer->AddActor(edgeActor);renderer->AddActor(boundaryActor);
}VTKFeatureEdge::~VTKFeatureEdge()
{}

运行结果:

在这里插入图片描述

实例 4:利用 vtkFillHolesFilter 补洞

vtkFillHolesFilter 是 VTK 中用于自动填充三角网格模型中洞的过滤器。vtkFillHolesFilter 支持多种数据格式,包括 vtkPolyData、vtkUnstructuredGrid、vtkStructuredGrid、vtkImageData 等。它还支持多种洞填充算法,包括 Delaunay 三角剖分、路径填充、平面填充等。使用 vtkFillHolesFilter 进行填洞时,可以保持原始模型的拓扑结构,避免生成不良的三角形。

vtkFillHolesFilter 的内部执行过程是首先检测出网格中的所有边界边,然后找出这些边界边中的每一个闭合回路,最后将这些闭合回路进行三角化(即生成三角网格)以实现填补的目的。这个类也是非常简单的,只需要设置需要填补的网格数据即可。

需要注意的是,有些边界的闭合回路是不需要三角化的,例如一个平面网格,若填补其四周的边界边,则会与原网格产生覆盖。vtkFillHolesFilters 中的 SetHoleSize() 函数可用于控制需要修补的漏洞面积的最大值,大于该值的漏洞则不需要填补处理。

#include "VTKFeatureEdge.h"#include <vtkBYUReader.h>
#include <vtkPlane.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkPolyData.h>
#include <vtkClipPolyData.h>
#include <vtkFeatureEdges.h>
#include <vtkStripper.h>
#include <vtkFillHolesFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>VTKFeatureEdge::VTKFeatureEdge(QWidget* parent): QMainWindow(parent)
{ui.setupUi(this);_pVTKWidget = new QVTKOpenGLNativeWidget();this->setCentralWidget(_pVTKWidget);vtkNew<vtkRenderer> renderer;this->_pVTKWidget->renderWindow()->AddRenderer(renderer);this->_pVTKWidget->renderWindow()->Render();vtkNew<vtkBYUReader> reader;reader->SetFileName("cow.g");reader->Update();// 截面vtkNew<vtkPlane> plane;plane->SetOrigin(reader->GetOutput()->GetCenter());plane->SetNormal(1.0, -1.0, -1.0); // 设置截面的法向量// 截取模型vtkNew<vtkClipPolyData> clipper;clipper->SetInputData(reader->GetOutput());clipper->SetClipFunction(plane); // 将 plane 设为 clipper 的截取函数clipper->SetValue(0.0);/*vtkNew<vtkFeatureEdges> featureEdges;featureEdges->SetInputConnection(clipper->GetOutputPort());featureEdges->BoundaryEdgesOn();featureEdges->ManifoldEdgesOff(); // 提取特征边设置打开featureEdges->NonManifoldEdgesOff();featureEdges->FeatureEdgesOff();featureEdges->ColoringOn(); // 显示颜色// 建立三角带对象vtkNew<vtkStripper> boundaryStrips;boundaryStrips->SetInputConnection(featureEdges->GetOutputPort()); // 将 featureEdges 生成的三角片连接成三角带boundaryStrips->Update();vtkNew<vtkPolyData> boundaryPolyData;boundaryPolyData->SetPoints(boundaryStrips->GetOutput()->GetPoints());boundaryPolyData->SetPolys(boundaryStrips->GetOutput()->GetLines());vtkNew<vtkPolyDataMapper> clipperMapper;clipperMapper->SetInputConnection(clipper->GetOutputPort());vtkNew<vtkPolyDataMapper> edgeMapper;edgeMapper->SetInputConnection(featureEdges->GetOutputPort());vtkNew<vtkPolyDataMapper> boundaryMapper;boundaryMapper->SetInputData(boundaryPolyData);vtkNew<vtkActor> clipperActor;clipperActor->SetMapper(clipperMapper);vtkNew<vtkActor> edgeActor;edgeActor->SetMapper(edgeMapper);vtkNew<vtkActor> boundaryActor;boundaryActor->SetMapper(boundaryMapper);renderer->AddActor(clipperActor);renderer->AddActor(edgeActor);renderer->AddActor(boundaryActor);*/vtkNew<vtkFillHolesFilter> fillHolesFilter;fillHolesFilter->SetInputConnection(clipper->GetOutputPort());fillHolesFilter->SetHoleSize(1000.0); // 大于该值的漏洞则不需要填补处理vtkNew<vtkPolyDataMapper> fillHolesMapper;fillHolesMapper->SetInputConnection(fillHolesFilter->GetOutputPort());vtkNew<vtkActor> fillHolesActor;fillHolesActor->SetMapper(fillHolesMapper);renderer->AddActor(fillHolesActor);
}VTKFeatureEdge::~VTKFeatureEdge()
{}

运行结果:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全局平均池化笔记

全局平均池化&#xff08;Global Average Pooling, GAP&#xff09;是一种用于卷积神经网络&#xff08;CNN&#xff09;中的池化操作&#xff0c;其主要作用和优点包括&#xff1a; 减少参数数量&#xff1a;全局平均池化层将每个特征图通过取其所有元素的平均值&#xff0c;压…

初识Spring Boot

初识Spring Boot SpringBoot是建立在Spring框架之上的一个项目,它的目标是简化Spring应用程序的初始搭建以及开发过程。 对比Spring Spring Boot作为Spring框架的一个模块&#xff0c;旨在简化Spring应用程序的初始搭建和开发过程&#xff0c;以下是Spring Boot相对于传统Spri…

[datawhale202405]从零手搓大模型实战:TinyAgent

结论速递 TinyAgent项目实现了一个简单的Agent智能体&#xff0c;主要是实现了ReAct策略&#xff08;推理调用工具的能力&#xff09;&#xff0c;及封装了一个Tool。 项目实现有一定的疏漏。为了正确运行代码&#xff0c;本次对代码Agent部分进行了简单修改&#xff08;完善…

【Linux】Linux的安装

文章目录 一、Linux环境的安装虚拟机 镜像文件云服务器&#xff08;可能需要花钱&#xff09; 未完待续 一、Linux环境的安装 我们往后的学习用的Linux版本为——CentOs 7 &#xff0c;使用 Ubuntu 也可以 。这里提供几个安装方法&#xff1a; 电脑安装双系统&#xff08;不…

关于burp的intruder返回包空白问题

记录一下被自己蠢笑的问题 burp返回包为空怎么办&#xff0c;在查询无果后经过多次试验&#xff0c;确实没有效果 看那三个点还以为加载呢&#xff0c;攻击完了怎么一个显示没有 于是…… 鼠标到三个点&#xff0c;往下一拉 哈哈哈哈哈哈哈&#xff0c;真是被自己给蠢到了

基于地理坐标的高阶几何编辑工具算法(2)——相交面裁剪

文章目录 工具步骤应用场景算法输入算法输出算法示意图算法原理后处理 工具步骤 选中一个需要裁剪的面&#xff0c;点击“相交面裁剪”工具&#xff0c;多选裁剪模板面&#xff0c;空格执行。 应用场景 常用于基于遥感影像的建筑物几何面编辑。 算法输入 一个待裁剪的面&a…

Mysql 备份恢复 mysqldump与xtrabackup备份

1.1 备份的原因 备份是数据安全的最后一道防线&#xff0c;对于任何数据丢失的场景&#xff0c;备份虽然不一定能恢复百分之百的数据 (取决于备份周期)&#xff0c;但至少能将损失降到最低。衡量备份恢复有两个重要的指标&#xff1a;恢复点目标(RPO) 和恢复时间目标(RTO)&…

vue+elemntui 加减表单框功能样式

<el-form ref"form" :model"form" :rules"rules" label-width"80px"><el-form-item label"配置时间" prop"currentAllocationDate"><div v-for"(item,key) in timeList"><el-date…

实验一:通过路由器实现内外网互联

通过路由器实现内外网互联 一、实验拓扑 相关配置详见下图&#xff0c;内网区域为AR2以内设备&#xff0c;外网区域以AR1和PC1代替进行实验测试。 二、实验要求 通过路由器实现内外网互联&#xff1a; 1.各内网PC可自动获取ip地址&#xff1b; 2.各内网PC可ping通外网PC&…

认知架构 cognitive architecture

Assistants API&#xff1a;以开发人员为中心。 有状态的API&#xff1a;允许存储以前的消息、上传文件、访问内置工具&#xff08;代码解释器&#xff09;、通过函数调用控制其他工具。 认知架构应用的两个组件&#xff1a;&#xff08;1&#xff09;如何提供上下文给应用 &…

【DevOps】深入了解RabbitMQ:AMQP协议基础、消息队列工作原理和应用场景

目录 一、核心功能 二、优势 三、核心概念 四、工作原理 五、交换机类型 六、消息确认 七、持久性和可靠性 八、插件和扩展 九、集群和镜像队列 十、客户端库 十一、管理界面 十二、应用场景 RabbitMQ是一个基于AMQP协议的消息队列中间件&#xff0c;提供高可用、可…

C++ | Leetcode C++题解之第112题路径总和

题目&#xff1a; 题解&#xff1a; class Solution { public:bool hasPathSum(TreeNode *root, int sum) {if (root nullptr) {return false;}if (root->left nullptr && root->right nullptr) {return sum root->val;}return hasPathSum(root->left…

el-table 划入划出方法

<template><div><el-table :data"tableData" style"width: 100%" cell-mouse-enter"handleMouseEnter" cell-mouse-leave"handleMouseLeave"><el-table-column prop"ddd" label"日期2" widt…

【TB作品】stm32单片机读取DS2401程序

DS2401是由Analog Devices公司生产的一种硅序列号芯片&#xff0c;它提供了一个绝对唯一的64位ROM识别码&#xff0c;用于确保可追溯性。以下是对DS2401器件的分析&#xff1a; 特点和优势&#xff1a; 唯一性&#xff1a;每个DS2401芯片都有一个独一无二的64位注册码&#x…

【实际项目精选源码】ehr人力资源管理系统实现案例(java,vue)

一、项目介绍 一款全源码可二开&#xff0c;可基于云部署、私有部署的企业级数字化人力资源管理系统&#xff0c;涵盖了招聘、人事、考勤、绩效、社保、酬薪六大模块&#xff0c;解决了从人事招聘到酬薪计算的全周期人力资源管理&#xff0c;符合当下大中小型企业组织架构管理运…

List Control控件绑定变量

创建基于对话框的mfc项目 添加 List Control控件 右击控件&#xff0c;选择“添加变量” 在初始化对话框代码中增加一些代码 BOOL CMFCApplication3Dlg::OnInitDialog() { //...// TODO: 在此添加额外的初始化代码DWORD dwStyle m_programLangList.GetExtendedStyle(); …

用户态下屏蔽全局消息钩子 —— ClientLoadLibrary 指针覆盖

目录 前言 一、研究 SetWindowsHookEx 的机制 二、概念验证 三、运行效果分析 四、总结与展望 参考文献 原文出处链接&#xff1a;[https://blog.csdn.net/qq_59075481/article/details/139206017] 前言 SetWindowsHookEx 函数帮助其他人员注入模块到我们的进程&#x…

PHP质量工具系列之php_CodeSniffer

PHP_CodeSniffer 是一组两个 PHP 脚本&#xff1a;主脚本 phpcs 对 PHP、JavaScript 和 CSS 文件进行标记&#xff0c;以检测是否违反定义的编码标准&#xff1b;第二个脚本 phpcbf 自动纠正违反编码标准的行为。PHP_CodeSniffer 是一个重要的开发工具&#xff0c;可以确保你的…

二叉树—先后序线索化和先后序线索遍历

有了上篇文章的基础&#xff0c;先序和后序的线索化逻辑一样。 代码如下&#xff1a; void preOrderThreadTree(TreeNode* T,TreeNode** pre) {if (T NULL) {;}else {//printf("%c ", T->val);if (T->lchild NULL) {T->ltag 1;T->lchild *pre;}if …

翻译《The Old New Thing》- What‘s the deal with the EM_SETHILITE message?

Whats the deal with the EM_SETHILITE message? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20071025-00/?p24693 Raymond Chen 2007年10月25日 简要 文章讨论了EM_SETHILITE和EM_GETHILITE消息在文档中显示为“未实现”的原因。这些…