vs2022结合qt6.5.3+pcl1.14.1打开pcd文件的一个例子
提前条件:已经安装vs2022,pcl1.14.1,qt6.5.3,并且已经配置pcl属性表,其中vtk是需要编译的
Pcl1.14.1对应的是VTK9.3,编译vtk的时候要选择With_QT

vs2022中安装qt插件

设置qt路径

设置此属性为true

实例开始:打开vs2022选择QtWidgetsApplication

项目名字自定义



下一步点Finish
双击UI文件

出来设计界面后,添加一个按钮pushButton_open,设置如下图

拖动一个openGLWidget到窗体上

右键点击openGLWidget选择提升为...

提升的类名称填:QVTKOpenGLNativeWidget,下面会自动填,然后点添加

全局包含打勾,再点提升

再添加一个进度条控件,保存并闭设计窗口


回到Visual Studio中右键点击UI文件--编译(UI中修改后都需要编译)

此时运行,可能会出现以下错误
无法打开包括文件: “QOpenGLWidget”: No such file or directory QtWidgetsPcd

添加如下图位置的内容
QT += openglwidgets

重新生成

给打开按钮添加槽(事件)

添加:pushButton_openClicked()


保存后,编译


在QtWidgetsPcd.h文件中添加以下代码

#pragma once
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
//点云数据存储
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;
//初始化vtk部件
void initialVtkWidget();
private slots:
void pushButton_openClicked(); //打开pcd文件的按钮

再修改QtWidgetsPcd.cpp文件
以下是修改前的截图

修改后的代码:
#include "QtWidgetsPcd.h"
#include <QFileDialog>
#include <iostream>
#include <vtkRenderWindow.h>
#include <QColorDialog>
#include "vtkGenericOpenGLRenderWindow.h"
#include "QVTKOpenGLNativeWidget.h"
#include <QFuture>
#include <QtConcurrent/QtConcurrent>
#include <pcl/io/vtk_lib_io.h>
#include <pcl/io/ply_io.h>
#pragma execution_character_set("utf-8")
QtWidgetsPcd::QtWidgetsPcd(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
initialVtkWidget();
ui.progressBar->setValue(0); // 初始化进度条
}
QtWidgetsPcd::~QtWidgetsPcd()
{}
void QtWidgetsPcd::initialVtkWidget()
{
cloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
auto renderer2 = vtkSmartPointer<vtkRenderer>::New();
auto renderWindow2 = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
renderWindow2->AddRenderer(renderer2);
cloud->resize(1);
viewer.reset(new pcl::visualization::PCLVisualizer(renderer2, renderWindow2, "viewer", false));
viewer->addPointCloud(cloud, "cloud");
// 添加坐标轴线条
double lineWidth = 0.8; // 坐标轴粗细
viewer->addLine<pcl::PointXYZ>(pcl::PointXYZ(0, 0, 0), pcl::PointXYZ(1, 0, 0), 1.0, 0.0, 0.0, "x_axis", lineWidth);
viewer->addLine<pcl::PointXYZ>(pcl::PointXYZ(0, 0, 0), pcl::PointXYZ(0, 1, 0), 0.0, 1.0, 0.0, "y_axis", lineWidth);
viewer->addLine<pcl::PointXYZ>(pcl::PointXYZ(0, 0, 0), pcl::PointXYZ(0, 0, 1), 0.0, 0.0, 1.0, "z_axis", lineWidth);
//添加X, Y, Z标注
viewer->addText3D("X", pcl::PointXYZ(1.1, 0, 0), 0.1, 1.0, 0.0, 0.0, "x_text");
viewer->addText3D("Y", pcl::PointXYZ(0, 1.1, 0), 0.1, 0.0, 1.0, 0.0, "y_text");
viewer->addText3D("Z", pcl::PointXYZ(0, 0, 1.1), 0.1, 0.0, 0.0, 1.0, "z_text");
ui.openGLWidget->setRenderWindow(viewer->getRenderWindow());
viewer->setupInteractor(ui.openGLWidget->interactor(), ui.openGLWidget->renderWindow());
ui.openGLWidget->update();
viewer->setBackgroundColor(0, 0, 0);
}
void QtWidgetsPcd::pushButton_openClicked()
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open PointCloud"), ".",
tr("Point Cloud Files (*.pcd *.ply *.stl)"));
if (!fileName.isEmpty())
{
ui.progressBar->setValue(0); // 重置进度条
QtConcurrent::run([this, fileName]() {
std::string file_name = fileName.toStdString();
std::string file_extension = file_name.substr(file_name.find_last_of('.') + 1);
if (file_extension == "pcd")
{
pcl::PCDReader reader;
reader.read(file_name, *cloud);
// 模拟解析过程中的进度更新
for (int i = 0; i < 100; i++)
{
QThread::msleep(10); // 模拟处理延时
QMetaObject::invokeMethod(this, [this, i]() {
ui.progressBar->setValue(i + 1);
}, Qt::QueuedConnection);
}
}
else if (file_extension == "ply")
{
pcl::io::loadPLYFile(file_name, *cloud);
// 模拟解析过程中的进度更新
for (int i = 0; i < 100; i++)
{
QThread::msleep(10); // 模拟处理延时
QMetaObject::invokeMethod(this, [this, i]() {
ui.progressBar->setValue(i + 1);
}, Qt::QueuedConnection);
}
}
else if (file_extension == "stl")
{
pcl::PolygonMesh mesh;
pcl::io::loadPolygonFileSTL(file_name, mesh);
pcl::fromPCLPointCloud2(mesh.cloud, *cloud);
// 模拟解析过程中的进度更新
for (int i = 0; i < 100; i++)
{
QThread::msleep(10); // 模拟处理延时
QMetaObject::invokeMethod(this, [this, i]() {
ui.progressBar->setValue(i + 1);
}, Qt::QueuedConnection);
}
}
QMetaObject::invokeMethod(this, [this]() {
viewer->updatePointCloud(cloud, "cloud");
viewer->resetCamera();
viewer->getRenderWindow()->Render(); // 强制渲染
viewer->setCameraPosition(
0, 0, 1, // 相机位置 (Z轴正方向朝屏幕)
0, 0, 0, // 目标点 (原点)
0, 1, 0 // 垂直方向 (Y轴垂直向上)
);
viewer->resetCamera();
ui.openGLWidget->update();
}, Qt::QueuedConnection);
});
}
}
重新生成,并运行,可以打开一个pcd文件测试

后续:
增加一个创建点云按钮 pushButton_New1


//创建点云星云
void QtWidgetsApplication3::pushButton_New1Clicked()
{
try {
// 创建新的RGB点云
pcl::PointCloud<pcl::PointXYZRGB>::Ptr rgb_cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
// 设置点云大小
rgb_cloud->width = 5000;
rgb_cloud->height = 1;
rgb_cloud->is_dense = false;
rgb_cloud->points.resize(rgb_cloud->width * rgb_cloud->height);
// 生成球面上的随机点,并为每个点设置颜色
srand(static_cast<unsigned int>(time(0)));
for (size_t i = 0; i < rgb_cloud->points.size(); ++i)
{
// 生成球面坐标
double theta = ((double)rand() / RAND_MAX) * 2.0 * M_PI; // 0 到 2π
double phi = acos(1 - 2 * ((double)rand() / RAND_MAX)); // 0 到 π
double radius = 5.0;
// 设置位置
rgb_cloud->points[i].x = radius * sin(phi) * cos(theta);
rgb_cloud->points[i].y = radius * sin(phi) * sin(theta);
rgb_cloud->points[i].z = radius * cos(phi);
// 基于位置设置渐变色
// 将球面坐标映射到RGB颜色空间
uint8_t r = static_cast<uint8_t>((sin(theta) + 1) * 127.5);
uint8_t g = static_cast<uint8_t>((cos(phi) + 1) * 127.5);
uint8_t b = static_cast<uint8_t>((cos(theta) + 1) * 127.5);
// 设置点的RGB颜色
rgb_cloud->points[i].r = r;
rgb_cloud->points[i].g = g;
rgb_cloud->points[i].b = b;
}
// 转换为XYZ点云以供显示
pcl::copyPointCloud(*rgb_cloud, *cloud);
// 移除旧的点云
viewer->removePointCloud("cloud");
// 使用RGB颜色处理器
pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(rgb_cloud);
viewer->addPointCloud<pcl::PointXYZRGB>(rgb_cloud, rgb, "cloud");
// 设置点云渲染属性
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud");
// 设置相机位置
viewer->setCameraPosition(
15, 15, 15, // 相机位置
0, 0, 0, // 目标点
0, 0, 1 // 上方向
);
// 重置相机和更新显示
viewer->resetCamera();
viewer->getRenderWindow()->Render();
ui.openGLWidget->update();
std::cout << "彩色点云生成成功!" << std::endl;
} catch (const std::exception& e) {
std::cerr << "生成点云时发生错误: " << e.what() << std::endl;
}
}


5340

被折叠的 条评论
为什么被折叠?



