当前位置:   article > 正文

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

pcl学习

注意事项

0. 效果演示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1. voxel_filtering.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108

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->removeAllPointClouds();
    cloud_viewer->removeAllShapes();

    for (size_t i = 0; i < vector_cloud.size(); ++i) {
        if (index[i] == 1) {
            pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> color_handler(vector_cloud[i], "z");
            cloud_viewer->addPointCloud(vector_cloud[i], color_handler, 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 || !item->isCheckable()) {
        return;
    }

    Qt::CheckState state = item->checkState();
    int cloudIndex = index.row();

    if (state == Qt::Checked) {
        cloud_index[cloudIndex] = 1;
    } else {
        cloud_index[cloudIndex] = 0;
    }

    view_updata(cloud_vec, cloud_index);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/518486
推荐阅读
相关标签
  

闽ICP备14008679号