VTK9.2.0+Qt5.14.0 绘制点云

news2024/11/18 4:40:03

背景

为了显示结构光重建后的点云,开发QT5.14.0+VTK9.2.0的上位机软件,用于对结构光3D相机进行控制,并接收传输回来的3D数据,显示在窗口中。

配置QT和VTK

VTK9.2.0下载源码,用Cmake编译,编译好的VTK9.2.0-vs2017在链接中:VTK9.2.0-vs2017编译工程

QT5.14.0下载链接
在这里插入图片描述

VTK绘制点云

VTK构造显示数据的基本流程是:
Point -> Cell -> Poly -> PolyMapper -> Actor -> Renderer -> QVTKOpenGLNativeWidget
其中,
⋅ \cdot vtkPoints类对应创建点数据,包含点的坐标,以及属性
⋅ \cdot vtkCellArray类是构造一种元素,比如三角网格,对应有三个point,那么一个cell中就会存储这三个point的索引值
⋅ \cdot vtkPolyData类是构造多边形元素
⋅ \cdot vtkActor类是构造“演员”
⋅ \cdot vtkRenderer类是构造着色器,理解为渲染场景的控制,包含“演员”、光源、背景等
⋅ \cdot vtkPolyDataMapper类将多边形元素和Actor建立联系
⋅ \cdot QVTKOpenGLNativeWidget类是渲染窗口控件
在qt中创建VTK渲染窗口控件有两种方式:
① 双击工程左侧.ui文件,在qt designer中创建ui.openGLWidget对象
在这里插入图片描述
ui.openGLWidget是通过qt designer,拖入QVTKWidget控件,右键该控件选择“提升窗口部件”,基类选择QOpenGLWidget, 提升的类名称为QVTKOpenGLNativeWidget, 在右上角的对象查看器中,重命名为openGLWidget. (注意:VTK8的创建方式是不一样的,注意版本)

在这里插入图片描述
② 方法二是直接用代码生成的方式,在工程的构造函数中直接new一个QVTKOpenGLNativeWidget对象,并设置其位置信息

QVtkDemo2::QVtkDemo2(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    //new一个QVTKOpenGLNativeWidget的对象
	ui.openGLWidget = new QVTKOpenGLNativeWidget(this);
	//设置渲染窗口的尺寸
	ui.openGLWidget->resize(100, 100); 
	 //设置左上角的在主窗口中的坐标
	ui.openGLWidget->move(50, 50);
	testVtk3D();
}

构造一个testVtk3D函数,用于绘制点云,并使用vtkCameraOrientationWidget类创建一个坐标轴对象,由于testVtk3D在构造函数中调用,需要在头文件中将其定义为全局变量。另外,VTK使用的是智能指针vtkSmartPointer,无需管理其释放问题,VTK还提供vtkNew类的智能指针,
vtkSmartPointer与vtkNew两者主要的使用区别在于:前者多用于全局变量,后者多用于局部变量

	//在头文件中定义为全局变量
	vtkSmartPointer<vtkCameraOrientationWidget> cameraOrientationWidget;
void QVtkDemo2::testVtk3D()
{
	//创建着色器对象
	vtkSmartPointer<vtkRenderer> g_vtkRenderer = vtkSmartPointer<vtkRenderer>::New();
	//设置背景颜色
	g_vtkRenderer->SetBackground(.1, .2, .4);
	//创建point对象
	vtkSmartPointer<vtkPoints> g_vtkPoints = vtkSmartPointer<vtkPoints>::New();
	//创建cell对象
	vtkSmartPointer<vtkCellArray> g_vtkVertices = vtkSmartPointer<vtkCellArray>::New();
	vtkIdType id[1];
	//随机生成200个点
	for (int i = 0; i < 200; i++)
	{
		float x = rand() % 10;
		float y = rand() % 10;
		float z = rand() % 10;
		id[0] = g_vtkPoints->InsertNextPoint(x, y, z);
		g_vtkVertices->InsertNextCell(1, id);
	}
	//创建poly对象
	vtkSmartPointer<vtkPolyData> g_vtkpolyData = vtkSmartPointer<vtkPolyData>::New();
	g_vtkpolyData->SetPoints(g_vtkPoints);
	g_vtkpolyData->SetVerts(g_vtkVertices);
	//创建polyMapper
	vtkSmartPointer<vtkPolyDataMapper> g_vtkpointsMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	g_vtkpointsMapper->SetInputData(g_vtkpolyData);
	//创建Actor
	vtkSmartPointer<vtkActor> g_vtkpointsActor = vtkSmartPointer<vtkActor>::New();
	g_vtkpointsActor->SetMapper(g_vtkpointsMapper);
	g_vtkpointsActor->GetProperty()->SetPointSize(3);//设置点的大小
	g_vtkRenderer->AddActor(g_vtkpointsActor);
	//根据点云的包围盒,寻找最佳的显示视点位置
	g_vtkRenderer->ResetCamera();
	//ui中的绘制窗口添加定义的着色器
	ui.openGLWidget->renderWindow()->AddRenderer(g_vtkRenderer);
	//开始三维渲染
	ui.openGLWidget->renderWindow()->Render();

	//绘制坐标轴
	cameraOrientationWidget = vtkSmartPointer<vtkCameraOrientationWidget>::New();
	cameraOrientationWidget->SetInteractor(ui.openGLWidget->interactor());
	cameraOrientationWidget->SetParentRenderer(g_vtkRenderer);
	cameraOrientationWidget->SetEnabled(1);

	return;
}

运行效果如下图
在这里插入图片描述

VTK根据Z值绘制点云颜色

void QVtkDemo2::testVtk3D()
{
	//创建着色器对象
	vtkSmartPointer<vtkRenderer> g_vtkRenderer = vtkSmartPointer<vtkRenderer>::New();
	//设置背景颜色
	g_vtkRenderer->SetBackground(.1, .2, .4);
	//创建point对象
	vtkSmartPointer<vtkPoints> g_vtkPoints = vtkSmartPointer<vtkPoints>::New();
	g_vtkPoints->SetNumberOfPoints(200);
	//创建cell对象
	vtkSmartPointer<vtkCellArray> g_vtkVertices = vtkSmartPointer<vtkCellArray>::New();
	vtkIdType id[1];
	//随机生成200个点
	float minz = VTK_FLOAT_MAX, maxz = VTK_FLOAT_MIN;
	for (int i = 0; i < 200; i++)
	{
		float x = rand() % 10;
		float y = rand() % 10;
		float z = rand() % 10;
		//提前申请了points的数量,使用set比insert速度更快
		g_vtkPoints->SetPoint(i, x, y, z);
		id[0] = i;
		g_vtkVertices->InsertNextCell(1, id);
		if (z > maxz)
		{
			maxz = z;
		}
		if (z < minz)
		{
			minz = z;
		}
	}
	//创建poly对象
	vtkSmartPointer<vtkPolyData> g_vtkpolyData = vtkSmartPointer<vtkPolyData>::New();
	g_vtkpolyData->SetPoints(g_vtkPoints);
	g_vtkpolyData->SetVerts(g_vtkVertices);

	vtkSmartPointer<vtkVertexGlyphFilter> g_glyphFilter = vtkSmartPointer<vtkVertexGlyphFilter>::New();
	g_glyphFilter->SetInputData(g_vtkpolyData);
	g_glyphFilter->Update();

	vtkSmartPointer<vtkElevationFilter> g_elevationFilter = vtkSmartPointer<vtkElevationFilter>::New();
	g_elevationFilter->SetInputConnection(g_glyphFilter->GetOutputPort());
	g_elevationFilter->SetLowPoint(0, 0, minz);
	g_elevationFilter->SetHighPoint(0, 0, maxz);

	//创建polyMapper
	vtkSmartPointer<vtkPolyDataMapper> g_vtkpointsMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	g_vtkpointsMapper->SetInputConnection(g_elevationFilter->GetOutputPort());

	//创建Actor
	vtkSmartPointer<vtkActor> g_vtkpointsActor = vtkSmartPointer<vtkActor>::New();
	g_vtkpointsActor->SetMapper(g_vtkpointsMapper);
	g_vtkpointsActor->GetProperty()->SetPointSize(3);//设置点的大小
	g_vtkRenderer->AddActor(g_vtkpointsActor);

	//建立查找表,将Z深度映射为一个查找表,表的值对应不同的颜色
	vtkNew<vtkLookupTable> lut = vtkNew<vtkLookupTable>::vtkNew();
	lut->SetNumberOfTableValues(7);
	lut->SetHueRange(0.0, 0.67); //这里是红到蓝,设置<0.67,1>为蓝到红
	lut->SetTableRange(minz, maxz);
	lut->Build();
	
	//创建色谱栏
	vtkNew<vtkScalarBarActor> colorBar = vtkNew<vtkScalarBarActor>::vtkNew();
	colorBar->SetLookupTable(lut);
	colorBar->SetNumberOfLabels(7);
	colorBar->SetBarRatio(0.10);
	colorBar->SetUnconstrainedFontSize(0.05);
	colorBar->SetMaximumHeightInPixels(100);
	colorBar->SetDisplayPosition(500, 80);
	g_vtkRenderer->AddActor2D(colorBar);

	//根据点云的包围盒,寻找最佳的显示视点位置
	g_vtkRenderer->ResetCamera();
	//ui中的绘制窗口添加定义的着色器
	ui.openGLWidget->renderWindow()->AddRenderer(g_vtkRenderer);
	//开始三维渲染
	ui.openGLWidget->renderWindow()->Render();

	//绘制坐标轴
	cameraOrientationWidget = vtkSmartPointer<vtkCameraOrientationWidget>::New();
	cameraOrientationWidget->SetInteractor(ui.openGLWidget->interactor());
	cameraOrientationWidget->SetParentRenderer(g_vtkRenderer);
	cameraOrientationWidget->SetEnabled(1);

	return;
}

在这里插入图片描述

VTK赋予点云真实纹理信息(灰度\彩色)

这个功能的需要,是因为重建点云是一个“白模”或像上一节中的深度颜色映射图一样,有时候会需要点云贴上相机拍摄的灰度纹理或彩色纹理。下面的代码中,我定义了vtkUnsignedCharArray的指针,对256个点,分别赋予了一个颜色,R=G=B的情况就是灰度。由此,可实现点云真实纹理的显示。

void QVtkDemo2::testVtk3D()
{
	//创建着色器对象
	vtkSmartPointer<vtkRenderer> g_vtkRenderer = vtkSmartPointer<vtkRenderer>::New();
	//设置背景颜色
	g_vtkRenderer->SetBackground(.1, .2, .4);
	//创建point对象
	vtkSmartPointer<vtkPoints> g_vtkPoints = vtkSmartPointer<vtkPoints>::New();
	g_vtkPoints->SetNumberOfPoints(256);
	//创建cell对象
	vtkSmartPointer<vtkCellArray> g_vtkVertices = vtkSmartPointer<vtkCellArray>::New();
	vtkIdType id[1];

	vtkSmartPointer<vtkUnsignedCharArray> ptColor = vtkSmartPointer<vtkUnsignedCharArray>::New();
	ptColor->SetNumberOfTuples(256);
	ptColor->SetNumberOfComponents(3);
	//随机生成256个点, 每个点一个灰度值
	float minz = VTK_FLOAT_MAX, maxz = VTK_FLOAT_MIN;
	for (int i = 0; i < 256; i++)
	{
		float x = rand() % 10;
		float y = rand() % 10;
		float z = rand() % 10;
		//提前申请了points的数量,使用set比insert速度更快
		g_vtkPoints->SetPoint(i, x, y, z);
		id[0] = i;
		g_vtkVertices->InsertNextCell(1, id);
		//赋予每一个点一个RGB值,R=G=B显示灰度,根据需要修改程序
		unsigned char rgb[3];
		rgb[0] = i;
		rgb[1] = i;
		rgb[2] = i;
		ptColor->InsertTypedTuple(i, rgb);
	}
	

	//创建poly对象
	vtkSmartPointer<vtkPolyData> g_vtkpolyData = vtkSmartPointer<vtkPolyData>::New();
	g_vtkpolyData->SetPoints(g_vtkPoints);
	g_vtkpolyData->SetVerts(g_vtkVertices);
	g_vtkpolyData->GetPointData()->SetScalars(ptColor);

	//创建polyMapper
	vtkSmartPointer<vtkPolyDataMapper> g_vtkpointsMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	g_vtkpointsMapper->SetInputData(g_vtkpolyData);

	//创建Actor
	vtkSmartPointer<vtkActor> g_vtkpointsActor = vtkSmartPointer<vtkActor>::New();
	g_vtkpointsActor->SetMapper(g_vtkpointsMapper);
	g_vtkpointsActor->GetProperty()->SetPointSize(3);//设置点的大小
	g_vtkRenderer->AddActor(g_vtkpointsActor);

	//根据点云的包围盒,寻找最佳的显示视点位置
	g_vtkRenderer->ResetCamera();
	//ui中的绘制窗口添加定义的着色器
	ui.openGLWidget->renderWindow()->AddRenderer(g_vtkRenderer);
	//开始三维渲染
	ui.openGLWidget->renderWindow()->Render();

	//绘制坐标轴
	cameraOrientationWidget = vtkSmartPointer<vtkCameraOrientationWidget>::New();
	cameraOrientationWidget->SetInteractor(ui.openGLWidget->interactor());
	cameraOrientationWidget->SetParentRenderer(g_vtkRenderer);
	cameraOrientationWidget->SetEnabled(1);

	return;
}

在这里插入图片描述

petal_20240322_142336

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

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

相关文章

Nacos介绍和Eureka的区别

Nacos&#xff08;全称为 Alibaba Cloud Nacos&#xff0c;或简称为 Nacos&#xff09;是一个开源的分布式服务发现和配置管理系统。它由阿里巴巴集团开发并开源&#xff0c;旨在帮助开发人员简化微服务架构下的服务注册、发现和配置管理。 1、Nacos 提供了以下主要功能&#…

短视频矩阵系统----源头开发

短视频矩阵源码技术开发要求及实现流程&#xff1a; 短视频矩阵开发要求具备视频录制、编辑、剪辑、分享等基本功能&#xff0c;支持实时滤镜、特效、音乐等个性化编辑&#xff0c;能够实现高效的视频渲染和处理。开发流程主要包括需求分析、技术选型、设计架构、编码实现、测试…

Binance labs孵化的Swan Chain明牌空投测试网零撸教程

简介&#xff1a;Swan Chain 是一个 Layer2云计算网络&#xff0c;可以将数据、计算、带宽和支付集成到一个套件&#xff0c;为Web3项目提供全面的解决方案。 相关概念&#xff1a;云计算、layer2、infrastructure 融资信息&#xff1a;项目在去年获得bi’an领投的300万美元融…

Flask 与小程序 的图片数据交互 过程及探讨研究学习

今天不知道怎么的&#xff0c;之前拿编程浪子地作品抄过来粘上用好好的&#xff0c;昨天开始照片突的就不显示了。 今天不妨再耐味地细细探究一下微信小程序wxml 和flask服务器端是怎么jpg图片数据交互的。 mina/pages/food/index.wxml <!--index.wxml--> <!--1px …

深度学习知识【CSPNet网络详解】

CSPNet的贡献 1.增强了CNN的学习能力&#xff0c;能够在轻量化的同时保持准确性。 2.降低计算瓶颈。 3.降低内存成本。 CSPNet介绍 在神经网络推理过程中计算量过高的问题是由于网络优化中的梯度信息重复导致的。CSPNet通过将梯度的变化从头到尾地集成到特征图中&#xff0c…

Golang案例开发之gopacket抓包三次握手四次分手(3)

文章目录 前言一、理论知识三次握手四次分手二、代码实践1.模拟客户端和服务器端2.三次握手代码3.四次分手代码验证代码完整代码总结前言 TCP通讯的三次握手和四次分手,有很多文章都在介绍了,当我们了解了gopacket这个工具的时候,我们当然是用代码实践一下,我们的理论。本…

如何在linux环境上部署单机ES(以8.12.2版本为例)

ES安装&#xff08;以8.12.2版本为例&#xff09; 首先创建好对应的文件夹然后在对应的文件夹下执行依次这些命令 1.wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.12.2-linux-x86_64.tar.gz 2.wget https://artifacts.elastic.co/downloads/…

002_avoid_for_loop_in_Matlab避免使用for循环

避免使用for循环 在程序设计思想中&#xff0c;循环是一个很有力的工具。在循环中&#xff0c;计算机很轻松地重复执行相同的操作。循环是汇编之上的编程中最重要的概念之一。Matlab的循环有两个语言构造&#xff0c;一个是for循环&#xff0c;另一个是while循环。在Matlab中&…

Git原理及使用

1、Git初识 Git是一种版本控制器: 对于同一份文件,做多次改动,Git会记录每一次改动前后的文件。 通俗的讲就是⼀个可以记录⼯程的每⼀次改动和版本迭代的⼀个管理系统,同时也⽅便多⼈协同作业。 注意: Git其实只能跟踪⽂本⽂件的改动,⽐如TXT⽂件,⽹⻚,所有的程序代码…

基于docker配置pycharm开发环境

开发过程中&#xff0c;为了做好环境隔离&#xff0c;经常会采用docker来进行开发&#xff0c;但是如何快速将docker中的环境和本地开发的IDE链接起来是一个常见问题&#xff0c;下面对其进行简单的总结&#xff1a; &#xff08;1&#xff09;前期准备 开发环境docker和工具p…

【练习】双指针算法思想

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;Java算法&#x1f4d5;格言&#xff1a;那些在暗处执拗生长的花&#xff0c;终有一日会馥郁传香欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 1. 移动零 1.1 题目描述 1.2 讲解算法原理 1.3 编…

STM32 AD单通道函数设计

单片机学习&#xff01; 目录 文章目录 前言 一、ADC配置步骤 二、详细步骤 2.1 开启RCC时钟 2.2 配置GPIO 2.3 配置多路开关 2.4 配置ADC转换器 2.5 开启ADC电源 2.6 ADC进行校准 2.6.1 复位校准 2.6.2 等待复位校准完成 2.6.3 开始校准 2.6.4 等待校准完成 三、启动AD转换函数…

数据结构大合集06——树与二叉树的相关函数运算算法

函数运算算法合集06 1、树的基本运算1.1 树的存储结构1.1.1 双亲存储结构1.1.2 孩子链存储结构1.1.3 孩子兄弟链式存储结构 2、二叉树的顺序存储2.1 二叉树顺序存储的结构体2.2 顺序存储的基本思路 3、二叉树的链式存储3.1 二叉树的链式存储的结构体3.2 链式存储的基本算法3.2.…

docker镜像复制与常见命令

一、前言 最近通过阿里的镜像仓库远程拉取镜像&#xff0c;发现以前的版本不见了&#xff0c;拉取了最新的镜像&#xff0c;有发现版本不配问题。那么想使用老版本的镜像那就要从别的环境获取。于是就需要进行离线镜像复制&#xff0c;打包&#xff0c;上传&#xff0c;重新导入…

时序预测 | Matlab实现BiTCN-GRU双向时间卷积神经网络结合门控循环单元时间序列预测

时序预测 | Matlab实现BiTCN-GRU双向时间卷积神经网络结合门控循环单元时间序列预测 目录 时序预测 | Matlab实现BiTCN-GRU双向时间卷积神经网络结合门控循环单元时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现BiTCN-GRU双向时间卷积神经网络结…

Tkinter 一文读懂

Tkinter 简介 Tkinter&#xff08;即 tk interface&#xff0c;简称“Tk”&#xff09;本质上是对 Tcl/Tk 软件包的 Python 接口封装&#xff0c;它是 Python 官方推荐的 GUI 工具包&#xff0c;属于 Python 自带的标准库模块&#xff0c;当您安装好 Python 后&#xff0c;就可…

AI新工具(20240322) 免费试用Gemini Pro 1.5;先进的AI软件工程师Devika;人形机器人Apptronik给你打果汁

✨ 1: Gemini Pro 1.5 免费试用Gemini Pro 1.5 Gemini 1.5 Pro是Gemini系列模型的最新版本&#xff0c;是一种计算高效的多模态混合专家&#xff08;MoE&#xff09;模型。它能够从数百万个上下文Token中提取和推理细粒度信息&#xff0c;包括多个长文档和数小时的视频、音频…

R语言逻辑回归与lasso模型

一、数据描述 数据集heart_learning.csv与heart_test.csv是关于心脏病的数据集&#xff0c;heart_learning.csv是训练数据集&#xff0c;heart_test.csv是测试数据集。 变量名称变量说明age年龄sex性别&#xff0c;取值1代表男性&#xff0c;0代表女性pain 胸痛的类型&#x…

SQLiteC/C++接口详细介绍sqlite3_stmt类(十二)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十一&#xff09; 下一篇&#xff1a; SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十三&#xff09; 48、sqlite3_stmt_isexplain sqlite3_stmt_is…

Django日志(四)

一、Filters介绍 过滤器用于从logger传递给handler的哪些日志要做额外控制 默认情况下,满足日志级别的任何消息都将处理。只要级别匹配,任何日志消息都会被处理。不过,也可以通过添加 filter 来给日志处理的过程增加额外条件。例如,可以添加一个 filter 只允许某个特定来源…