PCL结合QT5开发

PCL结合QT5开发

前言

在上一篇PCL安装与使用 介绍PCL简单使用过程,那么想在QT5项目中使用PCL项目模块该如何做呢!

1. 安装QT5

在mac系统下使用brew安装:

brew install qt@5

在mac系统下自动安装到/usr/local/Caller下面,导出qt相关的环境变量如下:

QT_HOME=/usr/local/Cellar/qt@5/5.15.3
exportPATH=$PATH:$QT_HOME/bin

同理ubuntu下可通过apt命令来对qt5进行安装。

2. 构建环境

在上文中我们添加了PCL的基本环境,修改其CMakeLists.txt文件,填写一下内容:

cmake_minimum_required(VERSION 3.23)
project(pcl-demo)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

# 引入QT框架 保证QT可以被CMaka搜索得到
set(CMAKE_PREFIX_PATH /usr/local/Cellar/qt@5/5.15.3/lib/cmake)

# 找到包PCL,引入模块visualization,io等模块,注意visualization模块可以自动将QT包含尽量,
find_package(PCL 1.3 REQUIRED COMPONENTS common io visualization filters)
message(STATUS "PCL_DIR = ${PCL_DIR}")
message(STATUS "PCL_INCLUDE_DIRS = ${PCL_INCLUDE_DIRS}")
message(STATUS "PCL_LIBS = ${PCL_LIBRARIES}")
message(STATUS "PCL_LIBRARY_DIRS = ${PCL_LIBRARY_DIRS}")
message(STATUS "PCL_VERSION = ${PCL_VERSION}")
message(STATUS "PCL_COMPONENTS = ${PCL_COMMON_LIBRARIES}")

add_definitions(${PCL_DEFINITIONS})
link_directories(${PCL_LIBRARY_DIRS})
include_directories(${PCL_INCLUDE_DIRS})

# 引入glog 框架
find_package(glog 0.6.0 REQUIRED)

# 引入 GTest 测试框架
include_directories(gtest/include)
link_directories(lib/gtest)

include_directories(src/main src/main/qt)
# 设置库函数的版本为 C++14
set(CMAKE_CXX_STANDARD 14)
# 搜索源文件
FILE(GLOB SRC *.cpp src/test/*.cpp src/main/*.cpp src/main/qt/*.cpp)
message(File Name:"${SRC}")

add_executable(${PROJECT_NAME} ${SRC})
target_link_libraries(${PROJECT_NAME} ${PCL_LIBRARIES} libgtest.a glog::glog)

将CMakeLists.txt修改完成后,通过cmake . 命令来进行构建项目。

3. QT界面

新建pclview.ui 界面通过QT designer对页面进行一个设计。打开后可以进行组件化的设计。如图所示:
QT界面设计
其他中间那一块是组件OpenGL Widget 组件,因为PCL也是通过OpenGL来进行绘画的。
在命令行里面执行命令:

uic pclview.ui -o PclViewer.h

其自动生成UI相关组件的代码。

4.创建界面窗口

在生成UI界面之后,我们可以通过组合的方式讲UI界面引入我们的逻辑处理中去,如下:

//
// Created by admin on 2023/1/30.
//

#ifndef PCL_DEMO_PCLVIEWER_H
#define PCL_DEMO_PCLVIEWER_H

#include <iostream>

// Qt
#include <QMainWindow>

#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>

// Visualization Toolkit (VTK)
#include <vtkRenderWindow.h>
#include "UI_PclViewer.h"

typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloudT;

namespace UI{
    class PclViewer:public QMainWindow{
    Q_OBJECT
    public:
        explicit PclViewer(QWidget * parent = nullptr);
        ~PclViewer() override;

        void refreshView();
    public Q_SLOTS:
        void randomButtonPressed();
        void loadFilePressed();

    private:
        Ui::PCLView *pclView;
        void connectSign();
    protected:
        pcl::visualization::PCLVisualizer::Ptr visualizer;
        PointCloudT ::Ptr pointCloud;
    };
}
#endif //PCL_DEMO_PCLVIEWER_H

这里我们新建了一个UI主窗口类,继承于QT的QMainWindow,因此这是个界面。然后在类中持有PointCloud的指针变量以及PCLVisualizer的指针变量,并且声明一些槽函数,用来处理一些点击事件。
以下为实现类:

//
// Created by admin on 2023/1/30.
//

#include "PclViewer.h"
#include "glog/logging.h"

#if VTK_MAJOR_VERSION > 8

#include <vtkGenericOpenGLRenderWindow.h>

#endif

#include <memory>
#include <QFileDialog>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/filters/filter.h>


UI::PclViewer::PclViewer(QWidget *parent) : QMainWindow(parent) {
    this->pclView = new Ui::PCLView;
    pclView->setupUi(this);
    this->pointCloud = std::make_shared<PointCloudT>();

    this->pointCloud->resize(500);
    for (int i = 0; i < pointCloud->size(); ++i) {
        this->pointCloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
        this->pointCloud->points[i].y = 1024* rand() /(RAND_MAX + 1.0f);
        this->pointCloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
    }

#if VTK_MAJOR_VERSION > 8
    auto renderer = vtkSmartPointer<vtkRenderer>::New();
    auto renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
    renderWindow->AddRenderer(renderer);
    this->visualizer = std::make_shared<pcl::visualization::PCLVisualizer>(renderer, renderWindow, "view", false);
    this->pclView->openGLWidget->setRenderWindow(this->visualizer->getRenderWindow());
    this->visualizer->setupInteractor(this->pclView->openGLWidget->interactor(), pclView->openGLWidget->renderWindow());
#else
    this->visualizer = std::make_shared<pcl::visualization::PCLVisualizer>("view",false);
    this->pclView->openGLWidget->setRenderWindow(this->visualizer->getRenderWindow());
    this->visualizer->setupInteractor(this->pclView->openGLWidget->interactor(),pclView->openGLWidget->renderWindow());
#endif
    pclView->openGLWidget->update();
    visualizer->addPointCloud(this->pointCloud);
    visualizer->resetCamera();
    this->connectSign();
    refreshView();
}

UI::PclViewer::~PclViewer() {
    delete this->pclView;
}

void UI::PclViewer::randomButtonPressed() {
    LOG(INFO) << "start click button";
}


void UI::PclViewer::connectSign() {
    connect(this->pclView->pushButton, SIGNAL(clicked(bool)), this, SLOT(randomButtonPressed()));
    connect(this->pclView->loadFileBtn, SIGNAL(clicked(bool)), this, SLOT(loadFilePressed()));

}

void UI::PclViewer::loadFilePressed() {
    QString filename = QFileDialog::getOpenFileName(this, tr("Open point cloud"), "/home/",
                                                    tr("Point cloud data (*.pcd *.ply)"));
    PCL_INFO("File chosen: %s\n", filename.toStdString().c_str());

    PointCloudT::Ptr cloud(new PointCloudT);
    if (filename.isEmpty()) return;

    int status = 0;
    if (filename.endsWith(".pcd", Qt::CaseInsensitive))
        status = pcl::io::loadPCDFile(filename.toStdString(), *cloud);
    else
        status = pcl::io::loadPLYFile(filename.toStdString(), *cloud);

    if (status != 0) {
        LOG(ERROR) << "Error reading point cloud";
        return;
    }

    if (cloud->is_dense) {
        pcl::copyPointCloud(*cloud, *this->pointCloud);
    } else {
        PCL_WARN("Cloud is not dense! Non finite points will be removed\n");
        std::vector<int> vec;
        pcl::removeNaNFromPointCloud(*cloud, *pointCloud, vec);
    }

    this->visualizer->updatePointCloud(this->pointCloud);
    this->visualizer->resetCamera();
    refreshView();
}

void UI::PclViewer::refreshView() {
#if VTK_MAJOR_VERSION > 8
    this->pclView->openGLWidget->renderWindow()->Render();
#else
    this->pclView->openGLWidget->update();
#endif
}

上述实现先将本类的指针进行初始话,由于VTK 8以上和VTK8以下的API的变动有些大,所以这里采用条件编译的方式,来区分VTK8的版本大小。

5.编译运行

在完成页面类后,按照一般QT程序的逻辑,将本界面引入到main函数里面,如下:

#include <pcl/common/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/cloud_viewer.h>

#include "PclViewer.h"
#include "QApplication"

int main(int argc, char **argv) {
    QSurfaceFormat::setDefaultFormat(QVTKOpenGLStereoWidget::defaultFormat());
    QApplication app(argc,argv);
    UI::PclViewer pclViewer;
    pclViewer.show();
    return QApplication::exec();
}

之后就是编译运行了,通过cmake,以及make命令来编译该项目。其运行为如下:
界面
通过Load File按钮可以加载相关点云数据。

相关代码下载

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

myenjoy_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值