提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
需求
最近老板分配了一个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,大佬们轻喷!