Qt PCL学习(三):点云滤波

注意事项

  • 版本一览:Qt 5.15.2 + PCL 1.12.1 + VTK 9.1.0
  • 前置内容:Qt PCL学习(一):环境搭建、Qt PCL学习(二):点云读取与保存

0. 效果演示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1. pcl_open_save.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

// 添加下行代码(根据自己安装目录进行修改)
include(D:/PCL1.12.1/pcl1.12.1.pri)

2. mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <voxel_filtering.h>
#include <vector>
#include <QMainWindow>
#include <QDebug>
#include <QColorDialog>
#include <QMessageBox>
#include <QFileDialog>
#include <QTime>
#include <QDir>
#include <QFile>
#include <QtMath>
#include <QWindow>
#include <QAction>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QIcon>
#include <QMenuBar>
#include <QMenu>
#include <QToolBar>
#include <QStatusBar>
#include <QFont>
#include <QString>
#include <QTextBrowser>
#include <QDirIterator>
#include <QStandardItemModel>
#include <QModelIndex>

#include "QVTKOpenGLNativeWidget.h"
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkNamedColors.h>
#include <vtkProperty.h>
#include <vtkSmartPointer.h>
#include "vtkAutoInit.h"

VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType);

#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/filters/voxel_grid.h>

#ifndef TREE_ITEM_ICON_DataItem
#define TREE_ITEM_ICON_DataItem QStringLiteral("treeItem_folder")
#endif

typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
typedef pcl::visualization::PCLVisualizer PCLViewer;
typedef std::shared_ptr<PointCloudT> PointCloudPtr;

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    PointCloudT::Ptr pcl_voxel_filter(PointCloudT::Ptr cloud_in, float leaf_size);
    void view_updata(std::vector<PointCloudT::Ptr> vector_cloud, std::vector<int> index);

private slots:
    void open_clicked();  // 打开文件
    void save_clicked();  // 保存文件

    void on_treeView_clicked(const QModelIndex &index);

    // 点云滤波
    void pressBtn_voxel();
    void voxel_clicked(QString data);

private:
    Ui::MainWindow *ui;

    QMap<QString, QIcon> m_publicIconMap;   // 存放公共图标

    QStandardItemModel* model;
    QStandardItem* itemFolder;

    QModelIndex index_cloud;
    std::vector<PointCloudT::Ptr> cloud_vec;
    std::vector<int> cloud_index;

    // 点云名称
    std::vector<std::string> cloud_name{"0", "1", "2"};
    int point_size = 1;

    PointCloudPtr cloudptr;
    PCLViewer::Ptr cloud_viewer;

    voxel_filtering *dialog_voxel;
};
#endif // MAINWINDOW_H

3. mainwindow.cpp

#pragma execution_character_set("utf-8")

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    // 设置窗口标题和 logo
    this->setWindowTitle("CloudOne");
    this->setWindowIcon(QIcon(":/resourse/icon.ico"));

    m_publicIconMap[TREE_ITEM_ICON_DataItem] = QIcon(QStringLiteral(":/resourse/folder.png"));
    model = new QStandardItemModel(ui->treeView);
    model->setHorizontalHeaderLabels(QStringList()<<QStringLiteral("--cloud--DB-Tree--"));
    ui->treeView->setHeaderHidden(true);

    ui->treeView->setModel(model);
    ui->treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);  // 设置多选

    cloudptr.reset(new PointCloudT);
    cloud_viewer.reset(new pcl::visualization::PCLVisualizer("viewer", false));
    vtkNew<vtkGenericOpenGLRenderWindow> window;
    window->AddRenderer(cloud_viewer->getRendererCollection()->GetFirstRenderer());
    ui->openGLWidget->setRenderWindow(window.Get());
    cloud_viewer->setupInteractor(ui->openGLWidget->interactor(), ui->openGLWidget->renderWindow());
    ui->openGLWidget->update();

    // 创建菜单栏
    QMenuBar *menu_bar = new QMenuBar(this);
    this->setMenuBar(menu_bar);
    menu_bar->setStyleSheet("font-size : 16px");

    // 1、File 下拉列表
    QMenu *file_menu = new QMenu("File", menu_bar);
    QAction *open_action = new QAction("Open File");
    QAction *save_action = new QAction("Save File");
    QAction *exit_action = new QAction("Exit");
    // 添加动作到文件菜单
    file_menu->addAction(open_action);
    file_menu->addAction(save_action);
    file_menu->addSeparator();  // 添加菜单分隔符将 exit 单独隔离开
    file_menu->addAction(exit_action);
    // 把 File 添加到菜单栏
    menu_bar->addMenu(file_menu);

    // 2、Filter 下拉列表
    QMenu *filter_menu = new QMenu("Filter", menu_bar);
    QAction *voxel_action = new QAction("Voxel Filtering");
    filter_menu->addAction(voxel_action);
    menu_bar->addMenu(filter_menu);


    // 信号与槽函数链接
    connect(open_action, SIGNAL(triggered()), this, SLOT(open_clicked()));  // 打开文件
    connect(save_action, SIGNAL(triggered()), this, SLOT(save_clicked()));  // 保存文件
    connect(exit_action, SIGNAL(triggered()), this, SLOT(close()));         // 退出
    connect(voxel_action, SIGNAL(triggered()), this, SLOT(pressBtn_voxel()));
}

MainWindow::~MainWindow() {
    delete ui;
}

PointCloudT::Ptr MainWindow::pcl_voxel_filter(PointCloudT::Ptr cloud_in, float leaf_size) {
    pcl::VoxelGrid<PointT> voxel_grid;
    voxel_grid.setLeafSize(leaf_size, leaf_size, leaf_size);
    voxel_grid.setInputCloud(cloud_in);
    PointCloudT::Ptr cloud_out (new PointCloudT()) ;
    voxel_grid.filter(*cloud_out);

    return cloud_out;
}

void MainWindow::pressBtn_voxel() {
    dialog_voxel = new voxel_filtering();
    connect(dialog_voxel, SIGNAL(sendData(QString)), this, SLOT(voxel_clicked(QString)));

    if (dialog_voxel->exec() == QDialog::Accepted){}

    delete dialog_voxel;
}

// 体素采样
void MainWindow::voxel_clicked(QString data) {
    if (cloudptr->empty()) {
        QMessageBox::warning(this, "Warning", "None point cloud!");
        return;
    } else {
        if (data.isEmpty()) {
            QMessageBox::warning(this, "Warning", "Wrong format!");
            return;
        }

        float size = data.toFloat();
        auto cloud_out = pcl_voxel_filter(cloudptr, size);
        cloudptr = cloud_out;

        int size1 = static_cast<int>(cloudptr->size());
        QString PointSize = QString("%1").arg(size1);

        ui->textBrowser_2->clear();
        ui->textBrowser_2->insertPlainText("PCD number: " + PointSize);
        ui->textBrowser_2->setFont(QFont("Arial", 9, QFont::Normal));

        cloud_viewer->removeAllPointClouds();
        cloud_viewer->removeAllShapes();
        cloud_viewer->addPointCloud<pcl::PointXYZ>(cloudptr->makeShared(), std::to_string(cloud_vec.size()-1));
        cloud_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, point_size, std::to_string(cloud_vec.size()-1));
        cloud_viewer->resetCamera();

        // 设置颜色处理器,将点云数据添加到 cloud_viewer 中
        const std::string axis = "z";
        pcl::visualization::PointCloudColorHandlerGenericField<PointT> color_handler(cloudptr, axis);
        cloud_viewer->addPointCloud(cloudptr, color_handler, "cloud");
        cloud_viewer->addPointCloud(cloudptr, "cloud");
    }
}

void MainWindow::open_clicked() {
    // this:代表当前对话框的父对象;tr("open file"):作为对话框的标题显示在标题栏中,使用 tr 函数表示这是一个需要翻译的文本
    // "":代表对话框的初始目录,这里为空表示没有指定初始目录
    // tr("pcb files(*.pcd *.ply *.txt) ;;All files (*.*)"):过滤器,决定在对话框中只能选择指定类型的文件
    QString fileName = QFileDialog::getOpenFileName(this, tr("open file"), "", tr("point cloud files(*.pcd *.ply) ;; All files (*.*)"));

    if (fileName.isEmpty()) {
        return;
    }
    if (fileName.endsWith("ply")) {
        qDebug() << fileName;
        if (pcl::io::loadPLYFile(fileName.toStdString(), *cloudptr) == -1) {
            qDebug() << "Couldn't read .ply file \n";
            return ;
        }
    } else if (fileName.endsWith("pcd")) {
        qDebug() << fileName;
        if (pcl::io::loadPCDFile(fileName.toStdString(), *cloudptr) == -1) {
            qDebug() << "Couldn't read .pcd file \n";
            return;
        }
    } else {
        QMessageBox::warning(this, "Warning", "Wrong format!");
    }

    cloud_vec.push_back(cloudptr->makeShared());
    cloud_index.push_back(1);

    itemFolder = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_folder")], QStringLiteral("cloud%1").arg(cloud_vec.size()-1));
    itemFolder->setCheckable(true);
    itemFolder->setCheckState(Qt::Checked);  // 获取选中状态
    model->appendRow(itemFolder);

    int size = static_cast<int>(cloudptr->size());
    QString PointSize = QString("%1").arg(size);

    ui->textBrowser_2->clear();
    ui->textBrowser_2->insertPlainText("PCD number: " + PointSize);
    ui->textBrowser_2->setFont(QFont("Arial", 9, QFont::Normal));

    cloud_viewer->addPointCloud<pcl::PointXYZ>(cloudptr->makeShared(), std::to_string(cloud_vec.size()-1));
    // 设置点云大小
    cloud_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, point_size, std::to_string(cloud_vec.size()-1));
    cloud_viewer->resetCamera();
    ui->openGLWidget->renderWindow()->Render();
    ui->openGLWidget->update();

    // 设置颜色处理器,将点云数据添加到 cloud_viewer 中
    const std::string axis = "z";
    pcl::visualization::PointCloudColorHandlerGenericField<PointT> color_handler(cloudptr, axis);
    cloud_viewer->addPointCloud(cloudptr, color_handler, "cloud");
    cloud_viewer->addPointCloud(cloudptr, "cloud");
}

void MainWindow::save_clicked() {
    int return_status;
    QString filename = QFileDialog::getSaveFileName(this, tr("Open point cloud"), "", tr("Point cloud data (*.pcd *.ply)"));

    if (cloudptr->empty()) {
        return;
    } else {
        if (filename.isEmpty()) {
            return;
        }
        if (filename.endsWith(".pcd", Qt::CaseInsensitive)) {
            return_status = pcl::io::savePCDFileBinary(filename.toStdString(), *cloudptr);
        } else if (filename.endsWith(".ply", Qt::CaseInsensitive)) {
            return_status = pcl::io::savePLYFileBinary(filename.toStdString(), *cloudptr);
        } else {
            filename.append(".ply");
            return_status = pcl::io::savePLYFileBinary(filename.toStdString(), *cloudptr);
        }
        if (return_status != 0) {
            PCL_ERROR("Error writing point cloud %s\n", filename.toStdString().c_str());
            return;
        }
    }
}

void MainWindow::view_updata(std::vector<PointCloudT::Ptr> vector_cloud, std::vector<int> index) {
    cloud_viewer.reset(new pcl::visualization::PCLVisualizer("viewer", false));
    vtkNew<vtkGenericOpenGLRenderWindow> window;
    window->AddRenderer(cloud_viewer->getRendererCollection()->GetFirstRenderer());
    ui->openGLWidget->setRenderWindow(window.Get());

    cloud_viewer->removeAllPointClouds();
    cloud_viewer->removeAllShapes();
    for (int i = 0; i<vector_cloud.size(); i++) {
        if (index[i] == 1) {
            pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ>render(vector_cloud[i], "intensity");
            cloud_viewer->addPointCloud<pcl::PointXYZ>(vector_cloud[i], render, std::to_string(i));
            cloud_viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, point_size, std::to_string(i));
        }
    }
    cloud_viewer->resetCamera();
    ui->openGLWidget->update();
}

// 确定 index
void MainWindow::on_treeView_clicked(const QModelIndex &index) {
    QStandardItem* item = model->itemFromIndex(index);

    // 点云数量更改
    QStandardItemModel* model = static_cast<QStandardItemModel*>(ui->treeView->model());
    QModelIndex index_temp = ui->treeView->currentIndex();

    int size = static_cast<int>(cloud_vec[index_temp.row()]->size());
    QString PointSize = QString("%1").arg(size);

    ui->textBrowser_2->clear();
    ui->textBrowser_2->insertPlainText("Point cloud number: " + PointSize);
    ui->textBrowser_2->setFont(QFont("Arial", 9, QFont::Normal));

    // 可视化更改
    if (item == nullptr)
        return;
    if (item->isCheckable()) {
        //判断状态
        Qt::CheckState state = item->checkState();  // 获取当前的选择状态
        if (Qt::Checked == state) {
            cloud_index[index.row()] = 1;
        }
        if (Qt::Unchecked == state) {
             cloud_index[index.row()] = 0;
        }
        view_updata(cloud_vec, cloud_index);
    }
}

4. voxel_filtering.h

#ifndef VOXEL_FILTERING_H
#define VOXEL_FILTERING_H

#include <QDialog>
#include <QString>

namespace Ui {
class voxel_filtering;
}

class voxel_filtering : public QDialog {
    Q_OBJECT

signals:
    void sendData(QString data);

public:
    explicit voxel_filtering(QWidget *parent = nullptr);
    ~voxel_filtering();

private slots:
    void on_buttonBox_accepted();

private:
    Ui::voxel_filtering *ui;
};

#endif // VOXEL_FILTERING_H

5. voxel_filtering.cpp

#include "voxel_filtering.h"
#include "ui_voxel_filtering.h"

voxel_filtering::voxel_filtering(QWidget *parent) : QDialog(parent), ui(new Ui::voxel_filtering) {
    ui->setupUi(this);
}

voxel_filtering::~voxel_filtering() {
    delete ui;
}

void voxel_filtering::on_buttonBox_accepted() {
    emit sendData(ui->lineEdit->text());

    this->close();
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Project 2010下载安装教程,保姆级教程,附安装包和工具

前言 Project是一款项目管理软件&#xff0c;不仅可以快速、准确地创建项目计划&#xff0c;而且可以帮助项目经理实现项目进度、成本的控制、分析和预测&#xff0c;使项目工期大大缩短&#xff0c;资源得到有效利用&#xff0c;提高经济效益。软件设计目的在于协助专案经理发…

除夕快乐(前端小烟花)

家人们&#xff0c;新的一年好运常在&#xff0c;愿大家在新的一年里得偿所愿&#xff0c;发财暴富&#xff0c;愿大家找到属于自己的那个公主&#xff0c;下面就给大家展示一下给公主的烟花 前端烟花 新的一年&#xff0c;新的挑战&#xff0c;愿我们不忘初心&#xff0c;砥砺…

谷歌发布AI新品Gemini及收费模式;宜家推出基于GPT的AI家装助手

&#x1f989; AI新闻 &#x1f680; 谷歌发布AI新品Gemini及收费模式 摘要&#xff1a;谷歌宣布将原有的AI产品Bard更名为Gemini&#xff0c;开启了谷歌的AI新篇章。同时推出了强化版的聊天机器人Gemini Advanced&#xff0c;支持更复杂的任务处理&#xff0c;提供了两个月的…

人力资源智能化管理项目(day04:组织架构)

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/humanResourceIntelligentManagementProject 觉得有帮助的同学&#xff0c;可以点心心支持一下哈 树组件应用 <!-- 展示树形结构 --><!-- default-expand-all默认展开所有节点 --><el-tree default-ex…

医学护理答案怎么查找? #笔记#学习方法#微信

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式&#xff0c;可以快速查找问题解析&#xff0c;加深对题目答案的理解。 1.滴墨书摘 这款软件相当于一个在线“摘抄本”&#xff0c;我们可以利用它来记录一些阅读时遇到的好句子或者是段落&#xff0c;或许下次…

Linux操作系统基础(五):Linux的目录结构

文章目录 Linux的目录结构 一、Linux目录与Windows目录区别 二、常见目录介绍&#xff08;记住重点&#xff09; Linux的目录结构 一、Linux目录与Windows目录区别 Linux的目录结构是一个树型结构 Windows 系统 可以拥有多个盘符, 如 C盘、D盘、E盘 Linux 没有盘符 这个概…

【DDD】学习笔记-领域模型与函数范式

函数范式 REA 的 Ken Scambler 认为函数范式的主要特征为&#xff1a;模块化&#xff08;Modularity&#xff09;、抽象化&#xff08;Abstraction&#xff09;和可组合&#xff08;Composability&#xff09;&#xff0c;这三个特征可以帮助我们编写简单的程序。 通常&#…

JavaScript综合练习4

JavaScript 综合练习 4 1. 案例演示 2. 代码实现 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title&…

ES实战-book笔记1

#索引一个文档,-XPUT手动创建索引, curl -XPUT localhost:9200/get-together/_doc/1?pretty -H Content-Type: application/json -d {"name": "Elasticsearch Denver","organizer": "Lee" } #返回结果 {"_index" : "g…

【GO语言卵细胞级别教程】03.条件与循环语句

注意&#xff1a;以下演示所用的项目&#xff0c;在第一章节已经介绍了&#xff0c;这里不做赘述 目录&#xff1a; 【GO语言卵细胞级别教程】03.条件与循环语句1.条件语句1.1 if语句1.1.1 单层if语句1.1.2 if-else语句1.1.3 if-else-if 语句1.1.4 if 嵌套 1.2 switch 语句1.1…

[office] 怎么在Excel2003菜单栏自定义一个选项卡 #其他#微信#知识分享

怎么在Excel2003菜单栏自定义一个选项卡 怎么在Excel2003菜单栏自定义一个选项卡 ①启动Excel2003&#xff0c;单击菜单栏--工具--自定义。 ②在自定义界面&#xff0c;我们单击命令标签&#xff0c;在类别中选择新菜单&#xff0c;鼠标左键按住新菜单&#xff0c;拖放到菜单栏…

【Linux笔记】动静态库的封装和加载

一、静态库的封装 我们在学习C语言阶段其实就已经知道一个可执行程序的形成过程分为预处理、编译、汇编、链接这四个阶段&#xff0c;而且也知道我们程序中使用的各种库其实是在链接的阶段加载的。 可我们那时候并不知道库是怎么被加载的&#xff0c;或者库是怎么形成的&…

高防服务器出租的优势及特点

高防服务器出租是指租用具备高防御能力的服务器&#xff0c;用于应对网络攻击、保护网站和数据安全。那么为什么会选择高防服务器出租&#xff0c;小编为您整理发布高防服务器出租的优势及特点。 高防服务器通常具备以下特点&#xff1a; 1. 高性能硬件配置&#xff1a;高防服务…

前端工程化面试题 | 01.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【软考】系统集成项目管理工程师(十五)文档和配置管理【2分】

一、 文档管理 二、配置管理 1、配置项 基线类型基线包括管理原则基线配置项所有设计文档和源程序向开发人员开放读取的权限非基线配置项项目的各类计划额报告向PM、CCB及相关人员开放所有配置项的操作权限应由CMO&#xff08;配置管理员&#xff09;严格管理 2、基线 3、配置…

[office] excel求乘积的公式和方法 #媒体#笔记#经验分享

excel求乘积的公式和方法 本文首先给出两个常规的excel求乘积的链接&#xff0c;然后再例举了一个文字和数字在同一单元格里面的excel求乘积的公式写法。 excel求乘积的方法分为两种&#xff0c;第一种是直接用四则运算的*来求乘积&#xff0c;另外一种就是使用PRODUCT乘积函数…

攻防世界 CTF Web方向 引导模式-难度1 —— 11-20题 wp精讲

PHP2 题目描述: 暂无 根据dirsearch的结果&#xff0c;只有index.php存在&#xff0c;里面也什么都没有 index.phps存在源码泄露&#xff0c;访问index.phps 由获取的代码可知&#xff0c;需要url解码(urldecode )后验证id为admin则通过 网页工具不能直接对字母进行url编码 …

LeetCode Python - 6.Z字形变换

文章目录 题目答案运行结果 题目 将一个给定字符串 s 根据给定的行数 numRows &#xff0c;以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “PAYPALISHIRING” 行数为 3 时&#xff0c;排列如下&#xff1a; P A H N A P L S I I G Y I R 之后&#xff0c;你的输…

部署monggodb单节点分片集群

分片技术,可以满足MongoDB数据量大量增长的需求。当MongoDB存储海量的数据时&#xff0c;一台机器可能不足以存储数据&#xff0c;也可能不足以提供可接受的读写吞吐量。这时&#xff0c;我们就可以通过在多台机器上分割数据&#xff0c;使得数据库系统能存储和处理更多的数据。…

用Python动态展示排序算法

文章目录 选择冒泡插入排序归并排序希尔排序 经常看到这种算法可视化的图片&#xff0c;但往往做不到和画图的人心灵相通&#xff0c;所以想自己画一下&#xff0c;本文主要实现归并排序和希尔排序&#xff0c;如果想实现其他算法可参考这篇 C语言实现各种排序算法[选择&#x…