VTK 数据处理:特征边提取

news2024/12/25 12:54:40

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_OBJECT

public:
	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_OBJECT

public:
	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.coloradmin.cn/o/1695767.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cs与msf权限传递以及mimikatz抓取win2012明文密码

简单的介绍 cs与msf的简单介绍 我查找过资料得出&#xff0c;Cobalt Strike 的前身是 Armitage&#xff0c;而 Armitage 又可以理解为 Metasploit Framework 的图形界面版&#xff0c;因此 Cobalt Strike 与 Metasploit Framework 在很多地方都是兼容的&#xff0c;所以我们便…

开源免费绘画软件—Krita

一、前言 Krita是一款自由开源的数字绘画软件&#xff0c;适用于Windows、macOS和Linux操作系统。它被广泛用于制作漫画、接景、材质和插画等多种类型的数字艺术作品。Krita的主要目标是提供合适的工具&#xff0c;让画师可以从头到尾完成一幅数字绘画作品的创作。 Krita具备强…

5. C++网络编程-UDP协议的实现

UDP是无连接的。 UDP Server网络编程基本步骤 创建socket&#xff0c;指定使用UDP协议将socket与地址和端口绑定使用recv/send接收/发送数据 由于UDP是无连接的&#xff0c;直接侦听就行使用close关闭连接 这个UDP接收数据的时候用的API是recvfrom,发送数据是sendto 客户端 …

检测头篇 | YOLOv8改进之添加小目标检测头 / 添加大目标检测头 / 减少检测头

前言:Hello大家好,我是小哥谈。本文首先给大家展示原始YOLOv8的网络结构图,然后再对其进行改变,即增加小目标检测头、增加大目标检测头和减少检测头。🌈 目录 🚀1.网络结构图

pikachu靶场中的CSRF、SSRF通关

目录 1、CSRF介绍 2、CSRF&#xff08;get&#xff09; 3、CSRF&#xff08;post&#xff09; 4、CSRF Token 5、SSRF介绍 6、SSRF&#xff08;curl&#xff09; 7、SSRF&#xff08;file_get-content&#xff09; 8、CSRF与SSRF的区别 最近在学习CSRF、SSRF漏洞&#…

ASP+ACCESS酒店房间预约系统设计

摘要 随着国内经济形势持续发展&#xff0c;国内酒店业进入难得的发展高峰期&#xff0c;使得中外资本家纷纷将目光投向中低端市场。然而&#xff0c;中国酒店业的区域结构不合理、竞争手段不足和市场对经济型酒店的需求日益显露&#xff0c;以及2008年北京奥运会、2010年上海…

【全网最全】2024电工杯数学建模A题成品论文+前三题完整解答matlab+py代码等(后续会更新成品论文)

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片链接&#xff0c;那是获取资料的入口&#xff01; 【全网最全】2024电工杯数学建模A题成品论文前三题完整解答matlabpy代码等&#xff08;后续会更新成品论文&#xff09;「首先来看看目前已有的资料&am…

Python | Leetcode Python题解之第112题路径总和

题目&#xff1a; 题解&#xff1a; class Solution:def hasPathSum(self, root: TreeNode, sum: int) -> bool:if not root:return Falseif not root.left and not root.right:return sum root.valreturn self.hasPathSum(root.left, sum - root.val) or self.hasPathSum…

微信小程序预览图片和H5使用canvas实现图片+蒙层+文字

1、效果 2.H5实现 <!--* Author: limingfang* Date: 2024-05-20 10:26:51* LastEditors: limingfang* LastEditTime: 2024-05-21 16:31:11* Description: --> <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8&q…

自动驾驶场景中的长尾问题怎么解决?

自动驾驶长尾问题是指自动驾驶汽车中的边缘情况&#xff0c;即发生概率较低的可能场景。感知的长尾问题是当前限制单车智能自动驾驶车辆运行设计域的主要原因之一。自动驾驶的底层架构和大部分技术问题已经被解决&#xff0c;剩下的5%的长尾问题&#xff0c;逐渐成了制约自动驾…

Rustdesk客户端源码编译

1.安装VCPKG windows平台vcpkg安装-CSDN博客 2.使用VCPKG安装: windows平台vcpkg安装-CSDN博客 配置VCPKG_ROOT环境变量: 安装静态库: ./vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static 静态库安装成…

Polar 上传

Polar 上传 开题&#xff0c;是一个文件上传界面 对文件后缀有过滤 测试了一下是黑名单&#xff0c;过滤了php相关的文件&#xff0c;但是没过滤.ini、.htaccess后缀的文件 对内容的过滤是<?、file&#xff0c;所以不能用.user.ini配置文件绕过 我们选择使用.htaccess配置…

React(四)memo、useCallback、useMemo Hook

目录 (一)memo API 1.先想一个情景 2.用法 (1)props传入普通数据类型的情况 (2)props传入对象的情况 (3)props传入函数的情况 (4)使用自定义比较函数 3.什么时候使用memo&#xff1f; (二)useMemo Hook 1.用法 2.useMemo实现组件记忆化 3.useMemo实现函数记忆化 …

python列表生成式的妙用:区间内奇数求和

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、案例背景 三、实现步骤 四、案例验证 五、总结 一、引言 在Python编程中&a…

vue实现页面渲染时候执行某需求

1. 前言 在之前的项目中&#xff0c;需要实现一个监控token是否过期从而动态刷新token的功能&#xff0c;然而在登录成功后创建的监控器会在浏览器刷新点击或者是通过导航栏输入网址时销毁... 2. 试错 前前后后始过很多方法&#xff0c;在这里就记录一下也许也能为各位读者排…

按月爬取天气数据可视化展示

从天气网分析,可以查询每个月的天气情况,这里按照url规则,传入年月,获取数据,最后进行可视化展示,最终效果: 下面是获取过程: 第一步: import requestsdef get_weather(month):url = f"https://lishi.tianqi.com/nanning/{month}.html"response = reques…

I.MX6ULL的官方 SDK 移植实验

系列文章目录 I.MX6ULL的官方 SDK 移植实验 I.MX6ULL的官方 SDK 移植实验 系列文章目录一、前言二、I.MX6ULL 官方 SDK 包简介三、硬件原理图四、试验程序编写4.1 SDK 文件移植4.2 创建 cc.h 文件4.3 编写实验代码 五、编译下载验证5.1编写 Makefile 和链接脚本5.2编译下载 一、…

运维 之 大文件分片刻录光盘

需求 因有些企业中涉及设备只能通过光盘介质方式拷贝文件&#xff0c;然而采购的单张光盘又不能确保存放下一些较大的文件&#xff0c;所以只能通过分片的方式逐个光盘存储。 Windows处理 1、安装压缩软件&#xff08;自行选择&#xff0c;这里使用WinRAR&#xff09;、Ultr…

在CentOS7上安装Oracle11

一、概述 Oracle有两种安装方式&#xff0c;桌面安装和静默安装。这里我采用桌面安装的方式。 不得不说&#xff0c;Oracle真的是我目前为止安装过的最麻烦的软件没有之一&#xff0c;比K8S还麻烦&#xff0c;Oracle&#xff0c;真有你的&#xff01;废话不多说&#xff0c;臭…

多级留言/评论的功能实现——Vue3前端篇

文章目录 思路分析封装组件父组件模板逻辑样式 子组件——二级留言模板逻辑样式 子组件——三级留言以上模板逻辑样式 留言组件的使用 写完论文了&#xff0c;来把评论的前端部分补一下。 前端的实现思路是自己摸索出来的&#xff0c;没找到可以符合自己需求的参考&#xff0c;…