创建 PCL + Qt 项目,我们将使用 Cmake 而不是 Qmake。
我们要编写的程序是一个简单的 PCL 可视化器,它允许更改随机生成的点云颜色。
Github代码地址
组织方式
.
├── build
└── src
├── CMakeLists.txt
├── main.cpp
├── pclviewer.cpp
├── pclviewer.h
├── pclviewer.ui
└── pcl_visualizer.pro
构建的第一步是使用参数调用cmake(从build文件夹中)…/src;这将在文件夹中创建所有文件, build而不修改文件夹中的任何内容src;从而保持清洁。
用户界面 (UI)
将 Qt 用于您的项目的目的是您可以轻松构建跨平台 UI。UI 保存在.ui文件中您可以使用gedit或 Qt Creator 打开它,在此示例中,UI 非常简单,它包括:
- QMainWindow , QWidget:应用程序的窗口(框架)
- qvtkWidget:包含 PCLVisualizer 的 VTK 小部件
- QLabel : 在用户界面上显示文本
- QSlider:用于选择值的滑块(此处为整数值)
- QLCDNumber : 数字显示,8 段样式
code parse:
main.cpp
#include "pclviewer.h"
#include <QApplication>
#include <QMainWindow>
int main (int argc, char *argv[])
{
QApplication a (argc, argv);
PCLViewer w;
w.show ();
return a.exec ();
}
这里我们包括类 PCLViewer 的头文件和 QApplication 和 QMainWindow 的头文件。
然后主要功能包括实例化一个 QApplication a来管理 GUI 应用程序的控制流和主要设置。
实例化一个名为wPCLViewer的对象并调用它的方法。show()
最后,我们通过 QApplication a返回程序退出的状态。
pclviewer.h
#pragma once
#include <iostream>
// Qt
#include <QMainWindow>
// Point Cloud Library
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
// Visualization Toolkit (VTK)
#include <vtkRenderWindow.h>
typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
这个文件是类 PCLViewer 的头文件;我们包括QMainWindow因为这个类包含 UI 元素,所以我们包括我们将使用的 PCL 头文件和qvtkWidget. 我们还定义了点类型和点云的 typedef,这提高了可读性。
namespace Ui
{
class PCLViewer;
}
我们在其中声明命名空间Ui和类 PCLViewer。
class PCLViewer : public QMainWindow
{
Q_OBJECT
这是 PCLViewer 类的定义;宏Q_OBJECT告诉编译器这个对象包含 UI 元素;这意味着该文件将通过Meta-Object Compiler (moc)进行处理。
public:
explicit PCLViewer (QWidget *parent = 0);
~PCLViewer ();
PCLViewer 类的构造函数和析构函数。
public Q_SLOTS:
void
randomButtonPressed ();
void
RGBsliderReleased ();
void
pSliderValueChanged (int value);
void
redSliderValueChanged (int value);
void
greenSliderValueChanged (int value);
void
blueSliderValueChanged (int value);
这些是公共时段;这些功能将与 UI 元素操作相关联。
protected:
pcl::visualization::PCLVisualizer::Ptr viewer;
PointCloudT::Ptr cloud;
unsigned int red;
unsigned int green;
unsigned int blue;
此处定义了指向 PCLVisualier 的 boost 共享指针和指向点云的指针。
整数red, green,blue将帮助我们存储滑块的值。
完整的.h代码
#pragma once
#include <iostream>
// Qt
#include <QMainWindow>
// Point Cloud Library
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
namespace Ui
{
class PCLViewer;
}
class PCLViewer : public QMainWindow
{
Q_OBJECT
public:
explicit PCLViewer (QWidget *parent = 0);
~PCLViewer ();
public Q_SLOTS:
void
randomButtonPressed ();
void
RGBsliderReleased ();
void
pSliderValueChanged (int value);
void
redSliderValueChanged (int value);
void
greenSliderValueChanged (int value);
void
blueSliderValueChanged (int value);
protected:
void
refreshView();
pcl::visualization::PCLVisualizer::Ptr viewer;
PointCloudT::Ptr cloud;
unsigned int red;
unsigned int green;
unsigned int blue;
private:
Ui::PCLViewer *ui;
};
下面分析 pclviewer.cpp
part1
#include "pclviewer.h"
#include "ui_pclviewer.h"
PCLViewer::PCLViewer (QWidget *parent) :
QMainWindow (parent),
ui (new Ui::PCLViewer)
{
ui->setupUi (this);
this->setWindowTitle ("PCL viewer");
// Setup the cloud pointer
cloud.reset (new PointCloudT);
// The number of points in the cloud
cloud->points.resize (200);
我们包括类头和 UI 对象的头;请注意,此文件由 moc 生成,其路径取决于您调用 cmake 的位置!
之后是构造函数实现;我们设置 ui 和窗口标题名称。| 然后我们在一个新分配的点云指针处初始化类的云指针成员。| 云的大小已调整为能够容纳 200 个点。
// The default color
red = 128;
green = 128;
blue = 128;
// Fill the cloud with some points
for (auto& point: *cloud)
{
point.x = 1024 * rand () / (RAND_MAX + 1.0f);
point.y = 1024 * rand () / (RAND_MAX + 1.0f);
point.z = 1024 * rand () / (RAND_MAX + 1.0f);
point.r = red;
point.g = green;
point.b = blue;
}
red green,blue受保护的成员被初始化为其默认值。
Point Cloud充满了随机点(在一个立方体中),并相应地赋予red greenblue值对应结果颜色。
// Set up the QVTK window
viewer.reset (new pcl::visualization::PCLVisualizer ("viewer", false));
ui->qvtkWidget->SetRenderWindow (viewer->getRenderWindow ());
viewer->setupInteractor (ui->qvtkWidget->GetInteractor (), ui->qvtkWidget->GetRenderWindow ());
ui->qvtkWidget->update ();
在这里,我们创建了一个 PCL Visualizer 名称viewer,并且我们还指定我们不希望创建交互器。
我们不希望创建一个交互器,因为我们qvtkWidget已经是一个交互器并且它是我们想要使用的交互器。
所以下一步是配置我们新创建的 PCL Visualiser 交互器以使用qvtkWidget.
每次修改 PCL 可视化工具时都应该调用的update()方法;qvtkWidget如果您不调用它,您不知道在用户尝试平移/旋转/缩放之前是否会更新可视化工具。
// Connect "random" button and the function
connect (ui->pushButton_random, SIGNAL (clicked ()), this, SLOT (randomButtonPressed ()));
// Connect R,G,B sliders and their functions
connect (ui->horizontalSlider_R, SIGNAL (valueChanged (int)), this, SLOT (redSliderValueChanged (int)));
connect (ui->horizontalSlider_G, SIGNAL (valueChanged (int)), this, SLOT (greenSliderValueChanged (int)));
connect (ui->horizontalSlider_B, SIGNAL (valueChanged (int)), this, SLOT (blueSliderValueChanged (int)));
connect (ui->horizontalSlider_R, SIGNAL (sliderReleased ()), this, SLOT (RGBsliderReleased ()));
connect (ui->horizontalSlider_G, SIGNAL (sliderReleased ()), this, SLOT (RGBsliderReleased ()));
connect (ui->horizontalSlider_B, SIGNAL (sliderReleased ()), this, SLOT (RGBsliderReleased ()));
// Connect point size slider
connect (ui->horizontalSlider_p, SIGNAL (valueChanged (int)), this, SLOT (pSliderValueChanged (int)));
在这里,我们连接槽和信号,这将 UI 操作与功能联系起来。以下是我们所链接内容的摘要:
- pushButton_random:
- 如果按下按钮呼叫randomButtonPressed ()
- horizontalSlider_R:
- 如果滑块值更改redSliderValueChanged(int),则以新值作为参数调用
如果滑块被释放调用RGBsliderReleased()
- 如果滑块值更改redSliderValueChanged(int),则以新值作为参数调用
- horizontalSlider_G:
- 如果滑块值更改redSliderValueChanged(int),则以新值作为参数调用
如果滑块被释放调用RGBsliderReleased()
- 如果滑块值更改redSliderValueChanged(int),则以新值作为参数调用
- horizontalSlider_B:
- 如果滑块值更改redSliderValueChanged(int),则以新值作为参数调用
如果滑块被释放调用RGBsliderReleased()
- 如果滑块值更改redSliderValueChanged(int),则以新值作为参数调用
viewer->addPointCloud (cloud, "cloud");
pSliderValueChanged (2);
viewer->resetCamera ();
ui->qvtkWidget->update ();
}
这是我们构造函数的最后一部分;我们将点云添加到可视化器中,
调用方法pSliderValueChanged将点大小更改为 2。
我们最终在 PCL Visualizer 中重置了相机,而不是避免用户必须缩小并更新 qvtkwidget 以确保显示修改。
void
PCLViewer::randomButtonPressed ()
{
printf ("Random button was pressed\n");
// Set the new color
for (auto& point: *cloud)
{
point.r = 255 *(1024 * rand () / (RAND_MAX + 1.0f));
point.g = 255 *(1024 * rand () / (RAND_MAX + 1.0f));
point.b = 255 *(1024 * rand () / (RAND_MAX + 1.0f));
}
viewer->updatePointCloud (cloud, "cloud");
ui->qvtkWidget->update ();
}
这是按下“随机”按钮时调用的公共槽函数成员。
for循环遍历点云并将点云颜色更改为随机数(0 到 255 之间)。
然后点云被更新,因此qtvtkwidget
也是如此。
void
PCLViewer::RGBsliderReleased ()
{
// Set the new color
for (auto& point: *cloud)
{
point.r = red;
point.g = green;
point.b = blue;
}
viewer->updatePointCloud (cloud, "cloud");
ui->qvtkWidget->update ();
}
这是每当释放红色、绿色或蓝色滑块时调用的公共槽函数成员
for循环遍历点云并将点云颜色更改为,red和green成员blue值。
然后点云被更新,因此qtvtkwidget
也是如此。
void
PCLViewer::redSliderValueChanged (int value)
{
red = value;
printf ("redSliderValueChanged: [%d|%d|%d]\n", red, green, blue);
}
void
PCLViewer::greenSliderValueChanged (int value)
{
green = value;
printf ("greenSliderValueChanged: [%d|%d|%d]\n", red, green, blue);
}
void
PCLViewer::blueSliderValueChanged (int value)
{
blue = value;
printf("blueSliderValueChanged: [%d|%d|%d]\n", red, green, blue);
}
这些是每当更改红色、绿色或蓝色滑块值时调用的公共槽函数成员
这些函数只是将成员值相应地更改为滑块值。
这里点云没有更新;因此,在您释放滑块之前,您不会在可视化工具中看到任何变化。
PCLViewer::~PCLViewer ()
{
delete ui;
}
析构函数。
完整pclviewer.cpp
#include "pclviewer.h"
#include "ui_pclviewer.h"
#if VTK_MAJOR_VERSION > 8
#include <vtkGenericOpenGLRenderWindow.h>
#endif
PCLViewer::PCLViewer (QWidget *parent) : QMainWindow (parent), ui (new Ui::PCLViewer)
{
ui->setupUi (this);
this->setWindowTitle ("PCL viewer");
// Setup the cloud pointer
cloud.reset (new PointCloudT);
// The number of points in the cloud
cloud->resize (200);
// The default color
red = 128;
green = 128;
blue = 128;
// Fill the cloud with some points
for (auto& point: *cloud)
{
point.x = 1024 * rand () / (RAND_MAX + 1.0f);
point.y = 1024 * rand () / (RAND_MAX + 1.0f);
point.z = 1024 * rand () / (RAND_MAX + 1.0f);
point.r = red;
point.g = green;
point.b = blue;
}
// Set up the QVTK window
#if VTK_MAJOR_VERSION > 8
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());
viewer->setupInteractor(ui->qvtkWidget->interactor(), ui->qvtkWidget->renderWindow());
#else
viewer.reset(new pcl::visualization::PCLVisualizer("viewer", false));
ui->qvtkWidget->SetRenderWindow(viewer->getRenderWindow());
viewer->setupInteractor(ui->qvtkWidget->GetInteractor(), ui->qvtkWidget->GetRenderWindow());
#endif
// Connect "random" button and the function
connect (ui->pushButton_random, SIGNAL (clicked ()), this, SLOT (randomButtonPressed ()));
// Connect R,G,B sliders and their functions
connect (ui->horizontalSlider_R, SIGNAL (valueChanged (int)), this, SLOT (redSliderValueChanged (int)));
connect (ui->horizontalSlider_G, SIGNAL (valueChanged (int)), this, SLOT (greenSliderValueChanged (int)));
connect (ui->horizontalSlider_B, SIGNAL (valueChanged (int)), this, SLOT (blueSliderValueChanged (int)));
connect (ui->horizontalSlider_R, SIGNAL (sliderReleased ()), this, SLOT (RGBsliderReleased ()));
connect (ui->horizontalSlider_G, SIGNAL (sliderReleased ()), this, SLOT (RGBsliderReleased ()));
connect (ui->horizontalSlider_B, SIGNAL (sliderReleased ()), this, SLOT (RGBsliderReleased ()));
// Connect point size slider
connect (ui->horizontalSlider_p, SIGNAL (valueChanged (int)), this, SLOT (pSliderValueChanged (int)));
viewer->addPointCloud (cloud, "cloud");
pSliderValueChanged (2);
viewer->resetCamera ();
refreshView();
}
void
PCLViewer::randomButtonPressed ()
{
printf ("Random button was pressed\n");
// Set the new color
for (auto& point: *cloud)
{
point.r = 255 *(1024 * rand () / (RAND_MAX + 1.0f));
point.g = 255 *(1024 * rand () / (RAND_MAX + 1.0f));
point.b = 255 *(1024 * rand () / (RAND_MAX + 1.0f));
}
viewer->updatePointCloud (cloud, "cloud");
refreshView();
}
void
PCLViewer::RGBsliderReleased ()
{
// Set the new color
for (auto& point: *cloud)
{
point.r = red;
point.g = green;
point.b = blue;
}
viewer->updatePointCloud (cloud, "cloud");
refreshView();
}
void
PCLViewer::pSliderValueChanged (int value)
{
viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, value, "cloud");
refreshView();
}
void
PCLViewer::refreshView()
{
#if VTK_MAJOR_VERSION > 8
ui->qvtkWidget->renderWindow()->Render();
#else
ui->qvtkWidget->update();
#endif
}
void
PCLViewer::redSliderValueChanged (int value)
{
red = value;
printf ("redSliderValueChanged: [%d|%d|%d]\n", red, green, blue);
}
void
PCLViewer::greenSliderValueChanged (int value)
{
green = value;
printf ("greenSliderValueChanged: [%d|%d|%d]\n", red, green, blue);
}
void
PCLViewer::blueSliderValueChanged (int value)
{
blue = value;
printf("blueSliderValueChanged: [%d|%d|%d]\n", red, green, blue);
}
PCLViewer::~PCLViewer ()
{
delete ui;
}
UI 界面
由qt designer 打开