Qt中添加VTK窗口并显示点云

我使用的版本是:
VS2019 + QT5.15.2 + VTK9.1

1. 在Qt中添加显示点云的控件

关于添加显示点云控件主要参考了以下链接:salute 链接

1.1 在designer中添加VTK窗口

添加完成之后注意在.sln项目中配置VTK库,否则无法#include <QVTKOpenGLNativeWidget.h>
方法的核心就是将QWidget提升为自定义控件。

QVTKOpenGLNativeWidget 实际上是VTK给写好的一个自定义控件,继承自QWidget类,所以只需要将QWdiget类提升为QVTKOpenGLNativeWidget类就行了

1.用Designer打开项目的界面文件(.ui后缀文件)

2.在左边的控件栏中,将Containers下的“Widget”这个控件拖入到用户界面中,然后右边的对象查看器中就能查到你拖入的QWidget控件对象。
img
3.对该对象点右键,选择“提升为”,提升为可以理解是将QT自带的控件类提升为开发者编写的自定义控件类。而QVTKOpenGLNativeWidget就是VTK编写的自定义控件类。
img
4.然后提升的类名称填上“QVTKOpenGLNativeWidget”,头文件填写“QVTKOpenGLNativeWidget.h”。基类选择QWidget。然后点击“添加”-》“提升”
img
提升的类名称: 指自定义控件的类名称,VTK提供的自定义类名称就是QVTKOpenGLNativeWidget。
头文件: 指自定义控件的头文件,VTK提供的自定义控件类的头文件就是QVTKOpenGLNativeWidget.h。注意大小写。如果不对应的话,会失效。
基类名称: 指自定义的控件类的基类是谁,QVTKOpenGLNativeWidget的基类就是QWidget。选错了也是不行的。
添加: 指保存这个设定,下次可以直接拿来使用,不用重新输入以上信息。
提升: 指将你拖入UI中的QWidget控件,变成你写好的自定义控件类,在这里就是将QWidget类变成QVTKOpenGLNativeWidget类。

5.重命名该窗口控件的对象名,用来写代码的时候识别。网上所见通常命名为“qvtkWidget”
img

6.最后在你的主窗口类下调用ui的成员变量可以成功呼出qvtkWidget这个vtk窗口控件。
img

1.2 直接以代码形式添加vtk窗口

这是最简单的方法了,不要用到.ui文件,不需要用到Designer,直接在代码上用。都不需要提升类,直接包含头文件后拿来用就行。

在MainWindow的构造函数中写代码:(不需要照抄,理解以下几行代码在干嘛即可)

	//初始化VTK窗口,命名为qvtkWidget(原理和QPushButton这种QT自带的控件一样,只是该控件由VTK提供,用法跟QPushButton是一样的)	QVTKOpenGLNativeWidget* qvtkWidget = new QVTKOpenGLNativeWidget();	//初始化VTK的渲染器,平时用的比较多是vtkRenderWindow,但是在QT中要改用vtkGenericOpenGLRenderWindow,实质上与vtkRenderWindow功能一致	vtkGenericOpenGLRenderWindow* renderWindow = vtkGenericOpenGLRenderWindow()::New();	//将渲染器加入到VTK窗口中。可以先写这一行,后续再将准备好的vtkRenderer加入到renderWindow中也是可以同步数据的	qvtkWidget->setRenderWindow(renderWindow);	//创建网格布局,只是为了方便布局,实际上可以直接调用qvtkwidget的baseSize函数指定窗口大小也行	QGridLayout* displayGrid = new QGridLayout(this);	displayGrid->addWidget(qvtkWidget);	this->setLayout(displayGrid);

需要在MainWindow头文件中包含vtkGenericOpenGLRenderWindow.h和QVTKOpenGLNativeWidget.h头文件。
理解上面的代码,自己在MainWindow构造函数中去使用(在其他地方用也没问题,用法一样)

2. 在添加好的控件上显示点云

在添加的控件上显示点云主要参考此链接:salute链接

2.1 代码

    //----------------------------qvtkWidget的初始化-----------------------------------    auto renderer = vtkSmartPointer<vtkRenderer>::New();    auto renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();    renderWindow->AddRenderer(renderer);    viewer.reset(new pcl::visualization::PCLVisualizer(renderer, renderWindow, "viewer", false));    ui->qvtkWidget->setRenderWindow(viewer->getRenderWindow());    //此处qvtkWidget是我这个窗口的名称,自定义的    viewer->setupInteractor(ui->qvtkWidget->interactor(), ui->qvtkWidget->renderWindow());     //----------------------------qvtkWidget的初始化-----------------------------------    //----------------------------初始化点云并显示-------------------------------------    //初始化一个点云    pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);    //加载点云文件    if (pcl::io::loadPCDFile("data/ceshi.pcd", *cloud) == -1)    {        std::cout << "打开文件失败" << std::endl;    }    //刷新显示窗口    ui->qvtkWidget->repaint();    //添加点云    viewer->addPointCloud(cloud, "cloud");    //刷新    ui->qvtkWidget->update();    //视角    viewer->resetCamera();    //----------------------------初始化点云并显示-------------------------------------

3. QVTKOpenGLNativeWidget.h的解释

原链接请参考QVTKOpenGLNativeWidget.h源文件

3.1 类QVTKOpenGLNativeWidget的简介:

QVTKOpenGLNativeWidget是QOpenGLWidget的子类,用于在Qt应用程序中承载一个vtkGenericOpenGLRenderWindow。

请注意,QVTKOpenGLNativeWidget只能与vtkGenericOpenGLRenderWindow一起使用。
这是因为QOpenGLWidget希望接管窗口管理和OpenGL上下文的创建。
使用vtkXRenderWindow或vtkWin32RenderWindow(以及其他特定于平台的vtkRenderWindow子类)进行可靠工作非常棘手且充满问题。

由于QVTKOpenGLNativeWidget使用QOpenGLWidget来创建OpenGL上下文,
它使用QSurfaceFormat(使用QOpenGLWidget::setFormat或QSurfaceFormat::setDefaultFormat进行设置)来创建适当的窗口和上下文。
您可以使用QVTKOpenGLNativeWidget::copyToFormat获取适用于vtkRenderWindow的QSurfaceFormat。

QVTKOpenGLNativeWidget的典型用法如下:

// 在初始化QApplication之前,设置默认的表面格式。QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());vtkNew<vtkGenericOpenGLRenderWindow> window;QPointer<QVTKOpenGLNativeWidget> widget = new QVTKOpenGLNativeWidget(...);widget->SetRenderWindow(window.Get());// 如果使用任何标准视图例如vtkContextView,则可以执行以下操作。vtkNew<vtkContextView> view;view->SetRenderWindow(window.Get());// 您可以继续使用`window`作为常规vtkRenderWindow,包括添加渲染器、演员等。

3.2 OpenGL上下文:

在QOpenGLWidget(QVTKOpenGLNativeWidget的父类)中,所有渲染都发生在帧缓冲对象中。因此,在渲染代码中必须小心,永远不要直接重新绑定默认帧缓冲,即ID为0。

QVTKOpenGLNativeWidget创建了一个内部的QOpenGLFramebufferObject,独立于父类创建的QOpenGLFramebufferObject,用于vtkRenderWindow进行渲染。
这种显式的双缓冲在避免VTK中仅在临时后备缓冲区上进行的渲染时(例如进行选择时)破坏在屏幕上组合的结果时非常有用。

3.3 处理渲染和绘制:

QWidget子类(包括QOpenGLWidget和QVTKOpenGLNativeWidget)在QWidget::paint中显示其内容,以响应绘制事件。
QOpenGLWidget子类应在QOpenGLWidget::paintGL中进行OpenGL渲染。
QWidget可能由于各种原因接收到绘制事件,包括小部件获得焦点/失去焦点,UI中的其他小部件(例如状态栏中的QProgressBar)的更新等。

在VTK应用程序中,每当vtkRenderWindow需要更新以进行新的渲染时,可以通过在其上调用vtkRenderWindow::Render来完成。
设置在渲染窗口上的vtkRenderWindowInteractor确保随着对影响渲染结果的交互发生,它会调用渲染窗口上的Render。

由于Qt中的paint可能被调用得比需要的频繁,我们避免了每次发生这种情况时可能昂贵的vtkRenderWindow::Render调用。相反,QVTKOpenGLNativeWidget依赖于VTK应用程序在需要更新渲染时在渲染窗口上调用vtkRenderWindow::Render。
paintGL只是将由最近一次渲染调用vtkRenderWindow::Render渲染的结果传递给Qt窗口系统以在屏幕上组合。

在某些情况下,可能仍然需要在paint中进行渲染,例如如果窗口的大小被调整或Qt必须重新创建OpenGL上下文。
在这些情况下,QVTKOpenGLNativeWidget::paintGL可以通过调用QVTKOpenGLNativeWidget::renderVTK请求进行渲染。

3.4 注意事项:

QVTKOpenGLNativeWidget不支持立体声,请使用QVTKOpenGLStereoWidget以获取立体声渲染支持。

QVTKOpenGLNativeWidget针对Qt版本5.5及以上版本进行了优化。

参考:QVTKOpenGLStereoWidget QVTKRenderWidget


标签: none

评论已关闭