0. 前言

1. 无新的系统环境

  • PCL-1.13.1,VTK-7.1。
  • 在通过源码编译安装 PCL 的同时,已经自动安装了 VTK,所以这里无需额外编译安装!
  • 这里我的 QT 设计界面如下,可以看到我的组件列表这里没有其他博客提到的 QVTKWidget,因为我是从 PCL 官方教程的 ui 文件复制来的,直接可以使用!

2. 源码解读

  • CMakeLists.txt 需要导入 OpenGL、VTK、PCL,在上一个教程的基础上添加如下:

      find_package(Qt5 COMPONENTS OpenGL Widgets REQUIRED)
      find_package(VTK 7.1 REQUIRED)
      # Import PCL
      find_package(PCL 1.13.1 REQUIRED)
      if(PCL_FOUND)
          message( STATUS "PCL_FOUND: " ${PCL_FOUND})
          message( STATUS "PCL_INCLUDE_DIRS: " ${PCL_INCLUDE_DIRS})
          message( STATUS "PCL_LIBRARY_DIRS: " ${PCL_LIBRARY_DIRS})
          include_directories(${PCL_INCLUDE_DIRS})
          link_directories(${PCL_LIBRARY_DIRS})
          add_definitions(${PCL_DEFINITIONS})
      else()
          message(err: PCL not found)
      endif()
    
      ament_target_dependencies(
          ${PROJECT_NAME}
          rclcpp
          rviz_common
          rviz_default_plugins
          rviz_rendering
          Boost
          VTK
          PCL) # 添加依赖的 ROS2 库
    
      target_link_libraries(${PROJECT_NAME}
              Qt5::Widgets
              ${VTK_LIBRARIES}
              ${PCL_LIBRARIES}
      )
    
  • 实现了 PCLView 这个类,包含头文件 QVTKWidget.h,它继承自 QVTKWidget ,再怎么继承,祖辈还是 QWidget ,这样我们就可以用到很多爷爷类的特性了,类的声明如下:
#ifndef PCLView_H
#define PCLView_H

#include <QWidget>
#include <QVTKWidget.h>

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>

class PCLView : public QVTKWidget
{
    Q_OBJECT
public:
    PCLView(QWidget *parent = nullptr);

    void refreshView(); // 刷新显示

    pcl::visualization::PCLVisualizer::Ptr _viewer; // 显示窗口

protected:


private:
    pcl::PointCloud<pcl::PointXYZ>::Ptr _cloud; // 点云变量

};

#endif // PCLView_H
  • 初始化函数的逻辑也很清晰:
    • 初始化显示窗口
    • 生成/读取点云
    • 显示点云
    • 设置窗口
    • 刷新窗口
#include "pclView.h"

PCLView::PCLView(QWidget *parent)
: QVTKWidget(parent)
{

    // 初始化显示窗口
    _viewer.reset(new pcl::visualization::PCLVisualizer("viewer", false));
    _viewer->setBackgroundColor(0, 0, 0);
    // _viewer->addCoordinateSystem(1.0);
    _viewer->initCameraParameters();
    _viewer->setCameraPosition(0, 0, 0, 0, -1, 0);


    // 读取点云文件
    _cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
    _cloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
    _cloud->resize (200);
    // 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);
    }

    // 显示点云
    _viewer->addPointCloud<pcl::PointXYZ>(_cloud, "cloud");
    _viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud");

    this->SetRenderWindow(_viewer->getRenderWindow());
    _viewer->setupInteractor(this->GetInteractor(), this->GetRenderWindow());

    refreshView();
}

void PCLView::refreshView()
{
#if VTK_MAJOR_VERSION > 8
  this->renderWindow()->Render();
#else
  this->update();
#endif
}
  • 为了让 rviz 和 vtk 窗口并排显示,我在 mainwindow.cpp 中进行了一些布局,并排显示的模块都可以参考下面这个布局,百试不爽:

      lidarView = new LidarView();
      QVBoxLayout * lidar_layout = new QVBoxLayout;
      lidar_layout->setSpacing(0);
      lidar_layout->setMargin(0);
      lidar_layout->addWidget(lidarView->_render_panel.get());
      ui->wdgtLidarView->setLayout(lidar_layout);
    
      pclView = new PCLView();
      QVBoxLayout * pcl_layout = new QVBoxLayout;
      pcl_layout->setSpacing(0);
      pcl_layout->setMargin(0);
      pcl_layout->addWidget(pclView);
      ui->qvtkWidget->setLayout(pcl_layout);
    
  • 在最终实现的 VTK 窗口继承了 PCL 显示窗口相同的功能,一些快捷键如下:
快捷键 功能
左键拖动 旋转视角
右键拖动 平移视角
滚轮滚动 缩放视图
+ 放大
- 缩小点的大小
Shift + + 增大点的大小
鼠标位置 + f 放大鼠标位置
o 切换放大缩小到上次滚轮缩放的大小
g 显示坐标轴
r 重置摄像机视角到默认位置

3. 参考链接

  1. pcl/doc/tutorials/content/sources/qt_visualizer at master · PointCloudLibrary/pcl (github.com)