【Qt+VS2015显示pcd 3D散点数据】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


需求

最近老板分配了一个QT界面显示pcd点云数据的任务,我收集了很多资料,大部分是都是QT+VS+PCL+VTK的解决方案。研究了一天,环境还没配好老板就跟我讲VTK太复杂,将来用的时候不方便。于是我换了思路,我发现pcd保存的是空间坐标点集合,这样一来我可以先用PCL读取3D数据,然后将数据传递到QT界面,虽然不是很好看,但是也可以实现界面显示效果了。

提示:以下是本篇文章正文内容,下面案例可供参考

一、要不要用VTK?

一开始我是打算用VTK的,但是发现VTK+PCL+QT+VS的环境太难配了,还是回归原始,利用QT的QtDataVisualization来显示我的3d散点数据。

二、步骤+思路

1.首先你的QT+VS+PCL的环境要配好

2.初始化空间坐标系

void MainWindow::initGraph3D()
{
    graph3D = new Q3DScatter();
    graphContainer = QWidget::createWindowContainer(graph3D); //Q3DBars继承自QWindow,必须如此创建
    //创建坐标轴
    QValue3DAxis *axisX = new QValue3DAxis;
    axisX->setTitle("Axis X");
    axisX->setTitleVisible(true);
    axisX->setAutoAdjustRange(true);
    graph3D->setAxisX(axisX);

    QValue3DAxis *axisY = new QValue3DAxis;
    axisY->setTitle("Axis Y");
    axisY->setTitleVisible(true);
    axisY->setAutoAdjustRange(true);
    graph3D->setAxisY(axisY);

    QValue3DAxis *axisZ = new QValue3DAxis;
    axisZ->setTitle("Axis Z");
    axisZ->setTitleVisible(true);
    axisZ->setAutoAdjustRange(true);
    graph3D->setAxisZ(axisZ);
// 设置坐标轴值域
    graph3D->axisX()->setRange(-600.0f, 800.0f);
    graph3D->axisY()->setRange(-600.0f, 800.0f);
    graph3D->axisZ()->setRange(-600.0f, 1000.0f);

    series = new QScatter3DSeries;
    series->setItemLabelFormat(QStringLiteral("@xLabel, @yLabel, @zLabel"));
    series->setMesh(QAbstract3DSeries::MeshCube);
    series->setItemSize(0.3f);
    graph3D->addSeries(series);
}

3.加载PCD数据(x,y,z的空间坐标点集合)

//包含的头文件
#include<pcl/visualization/cloud_viewer.h>
#include<iostream>//标准C++库中的输入输出类相关头文件。
#include<pcl/io/io.h>
#include<pcl/io/pcd_io.h>//pcd 读写类相关的头文件。
#include<pcl/io/ply_io.h>
#include<pcl/point_types.h> //PCL中支持的点类型头文件。

获取pcd数据代码

 QString curPath = QDir::currentPath();//系统当前目录
    QString aFileName = QFileDialog::getOpenFileName(this, tr("Open the file"), curPath,"(*.pcd)");
	std::string FileName = std::string((const char *)aFileName.toLocal8Bit()); // Qstring转string
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	//char strfilepath[256] = "D:\\VisionProjects\\clouddata\\up.pcd";
	if (-1 == pcl::io::loadPCDFile(FileName, *cloud)) {
		cout << "error input!" << endl;
		return;
	}
	cout << cloud->points.size() << endl;
    QVector<QVector3D> itemList;
    //保存3d数据
	for (int i = 0; i < cloud->points.size(); i++)
	{
			itemList.append(QVector3D(
				cloud->points[i].x,
				cloud->points[i].y,
				cloud->points[i].z));
	}

4.传3D参数

    QScatterDataArray *dataArray = new QScatterDataArray;//创建散点数组
    dataArray->resize(itemList.count());//散点数组的大小
    QScatterDataItem *ptrToDataArray = &dataArray->first();//定义数组指针头
    for (int i = 0; i < itemList.count(); i++) {
        ptrToDataArray->setPosition(itemList.at(i));
        ptrToDataArray++;
    }

    graph3D->seriesList().at(0)->dataProxy()->resetArray(dataArray);

完整代码如下(示例):
头文件
mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtDataVisualization>
#include <QtDataVisualization/q3dscatter.h>
#include <QtGui/QFont>
#include <QtCore/QPropertyAnimation>
#include <QtCore/QSequentialAnimationGroup>
#include <QtGui/QVector3D>

using namespace QtDataVisualization;

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_4_clicked();

private:
    Q3DScatter *graph3D;  //3维图表
    QWidget *graphContainer;
    QScatter3DSeries *series; //序列
    QScatterDataProxy *proxy; //数据代理

private:
    Ui::MainWindow *ui;
    void    initGraph3D();
};
#endif // MAINWINDOW_H

主窗口文件
mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <string.h>
#include <QSplitter>
#include <QFont>
#include <QColorDialog>
#include <Q3DCamera>
#include <QSlider>
#include <QFileDialog>
#include <QtDataVisualization>

#include<pcl/visualization/cloud_viewer.h>
#include<iostream>//标准C++库中的输入输出类相关头文件。
#include<pcl/io/io.h>
#include<pcl/io/pcd_io.h>//pcd 读写类相关的头文件。
#include<pcl/io/ply_io.h>
#include<pcl/point_types.h> //PCL中支持的点类型头文件。
#include <fstream>
#include <string>

//using namespace std;
void MainWindow::initGraph3D()
{
    graph3D = new Q3DScatter();
    graphContainer = QWidget::createWindowContainer(graph3D); //Q3DBars继承自QWindow,必须如此创建
    //创建坐标轴
    QValue3DAxis *axisX = new QValue3DAxis;
    axisX->setTitle("Axis X");
    axisX->setTitleVisible(true);
    axisX->setAutoAdjustRange(true);
    graph3D->setAxisX(axisX);

    QValue3DAxis *axisY = new QValue3DAxis;
    axisY->setTitle("Axis Y");
    axisY->setTitleVisible(true);
    axisY->setAutoAdjustRange(true);
    graph3D->setAxisY(axisY);

    QValue3DAxis *axisZ = new QValue3DAxis;
    axisZ->setTitle("Axis Z");
    axisZ->setTitleVisible(true);
    axisZ->setAutoAdjustRange(true);
    graph3D->setAxisZ(axisZ);

    graph3D->axisX()->setRange(-600.0f, 800.0f);
    graph3D->axisY()->setRange(-600.0f, 800.0f);
    graph3D->axisZ()->setRange(-600.0f, 1000.0f);

    series = new QScatter3DSeries;
    series->setItemLabelFormat(QStringLiteral("@xLabel, @yLabel, @zLabel"));
    series->setMesh(QAbstract3DSeries::MeshCube);
    series->setItemSize(0.3f);
    graph3D->addSeries(series);
   // memset(&m_profile_Head,0,sizeof(m_profile_Head));


}


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //渐变颜色按钮1
    QLinearGradient grBtoY(0,0,100,0);
    grBtoY.setColorAt(1.0,Qt::black);
    grBtoY.setColorAt(0.67,Qt::blue);
    grBtoY.setColorAt(0.33,Qt::red);
    grBtoY.setColorAt(0.0,Qt::yellow);

    QPixmap pm(186,22);
    QPainter pmp(&pm);
    pmp.setBrush(QBrush(grBtoY));
    pmp.setPen(Qt::NoPen);
    pmp.drawRect(0,0,186,22);
    ui->pushButton_2->setIcon(QIcon(pm));
    ui->pushButton_2->setIconSize(QSize(186,22));

    //渐变颜色按钮2
    QLinearGradient grBtoR(0,0,100,0);
    grBtoR.setColorAt(1.0,Qt::darkGreen);
    grBtoR.setColorAt(0.5,Qt::yellow);
    grBtoR.setColorAt(0.2,Qt::red);
    grBtoR.setColorAt(0.0,Qt::darkRed);

    pmp.setBrush(QBrush(grBtoR));
    pmp.setPen(Qt::NoPen);
    pmp.drawRect(0,0,186,22);
    ui->pushButton_3->setIcon(QIcon(pm));
    ui->pushButton_3->setIconSize(QSize(186,22));

    initGraph3D();  //初始化3D控件

    // 在窗口显示3D坐标
    QSplitter *splitter = new QSplitter(Qt::Horizontal);
    splitter->addWidget(ui->groupBox);
    splitter->addWidget(graphContainer);

    this->setCentralWidget(splitter);

}

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


void MainWindow::on_checkBox_2_clicked(bool checked)
{//图表的网格
    graph3D->activeTheme()->setGridEnabled(checked);
}

void MainWindow::on_checkBox_5_clicked(bool checked)
{//柱状图的光滑性
    series->setMeshSmooth(checked);

}

void MainWindow::on_checkBox_4_clicked(bool checked)
{//显示倒影
    graph3D->setReflection(checked);
}

void MainWindow::on_checkBox_8_clicked(bool checked)
{//轴标题
    graph3D->axisX()->setTitleVisible(checked);
    graph3D->axisY()->setTitleVisible(checked);
    graph3D->axisZ()->setTitleVisible(checked);
}


void MainWindow::on_checkBox_9_clicked(bool checked)
{//轴标题背景
    graph3D->activeTheme()->setLabelBorderEnabled(checked);
}

void MainWindow::on_checkBox_6_clicked(bool checked)
{//Z轴反向
    graph3D->axisY()->setReversed(checked);
}

void MainWindow::on_checkBox_clicked(bool checked)
{//图标背景
    graph3D->activeTheme()->setBackgroundEnabled(checked);
}

void MainWindow::on_spinBox_valueChanged(int arg1)
{//轴标签字体大小
    QFont font = graph3D->activeTheme()->font();
    font.setPointSize(arg1);
    graph3D->activeTheme()->setFont(font);
}

void MainWindow::on_comboBox_2_currentIndexChanged(int index)
{//设置主题
    Q3DTheme *currentTheme = graph3D->activeTheme();
    currentTheme->setType(Q3DTheme::Theme(index));
}

void MainWindow::on_pushButton_clicked()
{//单一曲面颜色
    QColor color = series->baseColor();
    color = QColorDialog::getColor(color);
    if(color.isValid())
    {
        series->setBaseColor(color);
        series->setColorStyle(Q3DTheme::ColorStyleUniform);
    }
}

void MainWindow::on_checkBox_7_clicked(bool checked)
{//项的标签
    series->setItemLabelVisible(checked);
}

void MainWindow::on_comboBox_3_currentIndexChanged(int index)
{//单点样式
    QAbstract3DSeries::Mesh aMesh;
    aMesh = QAbstract3DSeries::Mesh(index+1);
    series->setMesh(aMesh);
}

void MainWindow::on_comboBox_4_currentIndexChanged(int index)
{//选择模式
    switch(index)
    {
    case 0:
        graph3D->setSelectionMode(QAbstract3DGraph::SelectionNone);
        break;
    case 1:
        graph3D->setSelectionMode(QAbstract3DGraph::SelectionItem);
        break;
    case 2:
        graph3D->setSelectionMode(QAbstract3DGraph::SelectionItemAndRow | QAbstract3DGraph::SelectionSlice);
        break;
    case 3:
        graph3D->setSelectionMode(QAbstract3DGraph::SelectionItemAndColumn | QAbstract3DGraph::SelectionSlice);
    default:
        break;
    }
}

void MainWindow::on_checkBox_3_clicked(bool checked)
{//阴影
    if(checked)
        graph3D->setShadowQuality(QAbstract3DGraph::ShadowQualityMedium);
    else
        graph3D->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
}

void MainWindow::on_comboBox_currentIndexChanged(int index)
{//预览视角
    graph3D->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPreset(index));

}

void MainWindow::on_SliderV_2_valueChanged(int value)
{
    on_SliderH_valueChanged(value);
}


void MainWindow::on_SliderH_valueChanged(int value)
{
    Q_UNUSED(value);
    int xRot = ui->SliderH->value();
    int yRot = ui->SliderV->value();
    int zoom = ui->SliderV_2->value();
    graph3D->scene()->activeCamera()->setCameraPosition(xRot,yRot,zoom);
}

void MainWindow::on_SliderV_valueChanged(int value)
{
    on_SliderH_valueChanged(value);
}

void MainWindow::on_comboBox_5_currentIndexChanged(int index)
{
//    if(index==0)
//        series->setDrawMode(QScatter3DSeries::DrawWireframe);
//    else if(index==1)
//        series->setDrawMode(QSurface3DSeries::DrawSurface);
//    else
//        series->setDrawMode(QSurface3DSeries::DrawSurfaceAndWireframe);
}

void MainWindow::on_pushButton_2_clicked()
{//渐变颜色1
    QLinearGradient gr;
    gr.setColorAt(0.0,Qt::black);
    gr.setColorAt(0.33,Qt::blue);
    gr.setColorAt(0.67,Qt::red);
    gr.setColorAt(1.0,Qt::yellow);

    series->setBaseGradient(gr);
    series->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
}

void MainWindow::on_pushButton_3_clicked()
{
    QLinearGradient grGtoR;
    grGtoR.setColorAt(1.0,Qt::darkGreen);
    grGtoR.setColorAt(0.5,Qt::yellow);
    grGtoR.setColorAt(0.2,Qt::red);
    grGtoR.setColorAt(0.0,Qt::darkRed);

    series->setBaseGradient(grGtoR);
    series->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
}

void MainWindow::on_pushButton_4_clicked()
{
    QString curPath = QDir::currentPath();//系统当前目录
    QString aFileName = QFileDialog::getOpenFileName(this, tr("Open the file"), curPath,"(*.pcd)");
	std::string FileName = std::string((const char *)aFileName.toLocal8Bit()); // Qstring转string
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	//char strfilepath[256] = "D:\\VisionProjects\\clouddata\\up.pcd";
	if (-1 == pcl::io::loadPCDFile(FileName, *cloud)) {
		cout << "error input!" << endl;
		return;
	}
	cout << cloud->points.size() << endl;
	//cout << cloud->points[3] << endl;
	//ofstream OutFile("clouddata.txt");
    QVector<QVector3D> itemList;
	for (int i = 0; i < cloud->points.size(); i++)
	{
			itemList.append(QVector3D(
				cloud->points[i].x,
				cloud->points[i].y,
				cloud->points[i].z));
	}
	
    // Read data items from the file to QVector
    //QTextStream stream;
    QFile dataFile(":/data/data.txt");
    QFile dataFile("D:/AI/Projects/pcl_first_test/pcl_first_test/clouddata.txt");
    //QFile dataFile(aFileName);
    //if (dataFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
    //    stream.setDevice(&dataFile);
    //    while (!stream.atEnd()) {
    //        QString line = stream.readLine();
    //        if (line.startsWith("#")) // Ignore comments
    //            continue;
    //        QStringList strList = line.split(",", QString::SkipEmptyParts);
    //        // Each line has three data items: xPos, yPos and zPos value
    //        if (strList.size() < 3) {
    //            qWarning() << "Invalid row read from data:" << line;
    //            continue;
    //        }
    //        itemList.append(QVector3D(
    //                             strList.at(0).trimmed().toFloat(),
    //                             strList.at(1).trimmed().toFloat(),
    //                             strList.at(2).trimmed().toFloat()));
    //    }
    //} else {
    //    qWarning() << "Unable to open data file:" << dataFile.fileName();
    //}

    // Add data from the QVector to datamodel
    QScatterDataArray *dataArray = new QScatterDataArray;
    dataArray->resize(itemList.count());
    QScatterDataItem *ptrToDataArray = &dataArray->first();
    for (int i = 0; i < itemList.count(); i++) {
        ptrToDataArray->setPosition(itemList.at(i));
        ptrToDataArray++;
    }

    graph3D->seriesList().at(0)->dataProxy()->resetArray(dataArray);
}

5.效果

代码如下(示例):
未加载数据的界面图

加载数据图


总结

这个效果没有直接调用PCL的视觉效果好,今后再找更好的办法。
第一次写CSDN,大佬们轻喷!

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值