使用 PCL 和 Qt 实现点云可视化与交互

下面我将介绍如何结合点云库(PCL)和Qt框架(特别是QML)来实现点云的可视化与交互功能,包括高亮选择等效果。

1. 基本架构设计

首先需要建立一个结合PCL和Qt的基本架构:

// PCLQtViewer.h
#pragma once#include <QObject>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>class PCLQtViewer : public QObject
{Q_OBJECTpublic:explicit PCLQtViewer(QObject* parent = nullptr);// 加载点云Q_INVOKABLE void loadPointCloud(const QString& filePath);// 获取点云数据供QML使用Q_INVOKABLE QVariantList getPointCloudData() const;// 高亮选择的点Q_INVOKABLE void highlightPoints(const QVariantList& indices);signals:void pointCloudLoaded();void selectionChanged();private:pcl::PointCloud<pcl::PointXYZRGB>::Ptr m_cloud;std::vector<int> m_selectedIndices;
};

2. PCL与Qt的集成实现

// PCLQtViewer.cpp
#include "PCLQtViewer.h"
#include <pcl/io/pcd_io.h>
#include <pcl/common/colors.h>PCLQtViewer::PCLQtViewer(QObject* parent) : QObject(parent), m_cloud(new pcl::PointCloud<pcl::PointXYZRGB>())
{
}void PCLQtViewer::loadPointCloud(const QString& filePath)
{if (pcl::io::loadPCDFile<pcl::PointXYZRGB>(filePath.toStdString(), *m_cloud) == -1) {qWarning() << "Failed to load PCD file";return;}emit pointCloudLoaded();
}QVariantList PCLQtViewer::getPointCloudData() const
{QVariantList points;for (const auto& point : *m_cloud) {QVariantMap pt;pt["x"] = point.x;pt["y"] = point.y;pt["z"] = point.z;pt["r"] = point.r;pt["g"] = point.g;pt["b"] = point.b;pt["selected"] = std::find(m_selectedIndices.begin(), m_selectedIndices.end(), &point - &m_cloud->points[0]) != m_selectedIndices.end();points.append(pt);}return points;
}void PCLQtViewer::highlightPoints(const QVariantList& indices)
{m_selectedIndices.clear();for (const auto& idx : indices) {m_selectedIndices.push_back(idx.toInt());}emit selectionChanged();
}

3. QML点云可视化界面

qml

// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import Qt3D.Core 2.15
import Qt3D.Render 2.15
import Qt3D.Input 2.15
import Qt3D.Extras 2.15ApplicationWindow {id: windowwidth: 1280height: 720visible: truePCLQtViewer {id: pclVieweronPointCloudLoaded: pointCloudModel.reload()onSelectionChanged: pointCloudModel.reload()}// 3D视图Qt3DWindow {id: view3danchors.fill: parentCamera {id: cameraprojectionType: CameraLens.PerspectiveProjectionfieldOfView: 45aspectRatio: view3d.width / view3d.heightnearPlane: 0.1farPlane: 1000.0position: Qt.vector3d(0.0, 0.0, 10.0)upVector: Qt.vector3d(0.0, 1.0, 0.0)viewCenter: Qt.vector3d(0.0, 0.0, 0.0)}// 点云实体Entity {id: pointCloudEntitycomponents: [Transform {id: cloudTransformscale: 1.0},GeometryRenderer {id: pointGeometryprimitiveType: GeometryRenderer.Pointsgeometry: Geometry {boundingVolumePositionAttribute: positionAttribute {id: positionattributeType: Attribute.VertexAttributevertexBaseType: Attribute.FloatvertexSize: 3byteOffset: 0byteStride: 6 * 4count: pointCloudModel.countbuffer: pointBuffer}Attribute {id: colorattributeType: Attribute.ColorAttributevertexBaseType: Attribute.FloatvertexSize: 3byteOffset: 3 * 4byteStride: 6 * 4count: pointCloudModel.countbuffer: pointBuffer}Buffer {id: pointBufferdata: pointCloudModel.geometryData}}},Material {effect: Effect {techniques: Technique {renderPasses: RenderPass {shaderProgram: ShaderProgram {vertexShaderCode: "#version 330in vec3 vertexPosition;in vec3 vertexColor;out vec3 color;uniform mat4 mvp;void main() {color = vertexColor;gl_Position = mvp * vec4(vertexPosition, 1.0);gl_PointSize = 3.0;}"fragmentShaderCode: "#version 330in vec3 color;out vec4 fragColor;void main() {fragColor = vec4(color, 1.0);}"}}}}}]}OrbitCameraController {camera: camera}}// 点云数据模型ListModel {id: pointCloudModelfunction reload() {clear();var points = pclViewer.getPointCloudData();for (var i = 0; i < points.length; i++) {append(points[i]);}}property var geometryData: {var data = new Float32Array(count * 6);for (var i = 0; i < count; i++) {var pt = get(i);data[i * 6] = pt.x;data[i * 6 + 1] = pt.y;data[i * 6 + 2] = pt.z;// 选中的点显示为红色,否则使用原始颜色if (pt.selected) {data[i * 6 + 3] = 1.0;data[i * 6 + 4] = 0.0;data[i * 6 + 5] = 0.0;} else {data[i * 6 + 3] = pt.r / 255.0;data[i * 6 + 4] = pt.g / 255.0;data[i * 6 + 5] = pt.b / 255.0;}}return data;}}// 控制面板Rectangle {width: 300height: parent.heightcolor: "#eee"Column {spacing: 10padding: 10Button {text: "加载点云"onClicked: fileDialog.open()}ListView {id: selectionListViewwidth: parent.widthheight: 200model: ListModel {}delegate: ItemDelegate {width: parent.widthtext: "点 " + indexhighlighted: pointCloudModel.get(index).selectedonClicked: {pclViewer.highlightPoints([index]);}}}}}FileDialog {id: fileDialogtitle: "选择点云文件"folder: shortcuts.homenameFilters: ["PCD文件 (*.pcd)"]onAccepted: pclViewer.loadPointCloud(fileDialog.fileUrl)}
}

4. 主程序集成

cpp

// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "PCLQtViewer.h"int main(int argc, char *argv[])
{QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);qmlRegisterType<PCLQtViewer>("PCL", 1, 0, "PCLQtViewer");QQmlApplicationEngine engine;engine.load(QUrl(QStringLiteral("qrc:/main.qml")));if (engine.rootObjects().isEmpty())return -1;return app.exec();
}

5. 高级功能扩展

点云聚类高亮

cpp

// 在PCLQtViewer类中添加
Q_INVOKABLE void highlightCluster(int clusterId)
{// 假设已经执行过聚类算法,结果存储在m_clusterIndices中m_selectedIndices = m_clusterIndices[clusterId];emit selectionChanged();
}

3D框选功能

qml

// 在Qt3DWindow中添加
Entity {components: [ObjectPicker {id: pickerdragEnabled: trueonClicked: {var worldPos = pick.worldPosition;// 转换坐标并选择附近的点pclViewer.selectPointsInSphere(worldPos.x, worldPos.y, worldPos.z, 0.5);}onPressed: {// 开始框选selectionRect.visible = true;selectionRect.x = pick.x;selectionRect.y = pick.y;}onReleased: {// 结束框选selectionRect.visible = false;var selected = selectPointsInRectangle(selectionRect);pclViewer.highlightPoints(selected);}}]
}Rectangle {id: selectionRectvisible: falsecolor: "#8033B5E5"border.color: "#0033B5E5"
}

点云着色模式切换

qml

ComboBox {model: ["原始颜色", "高度着色", "曲率着色", "聚类着色"]onCurrentIndexChanged: pclViewer.setColorMode(currentIndex)
}

6. 性能优化建议

  1. 点云分块加载:对于大型点云,实现分块加载机制

  2. LOD(细节层次):根据视点距离动态调整显示细节

  3. 后台处理:将PCL处理任务放在后台线程

  4. GPU加速:使用计算着色器处理点云数据

  5. 空间索引:使用八叉树等结构加速空间查询

7. 项目配置(CMake)

cmake_minimum_required(VERSION 3.5)project(PCL_Qt_Viewer)find_package(Qt5 COMPONENTS Quick QuickControls2 3DCore 3DRender 3DInput 3DExtras REQUIRED)
find_package(PCL 1.8 REQUIRED)set(CMAKE_AUTOMOC ON)
set(CMAKE_CXX_STANDARD 14)add_executable(${PROJECT_NAME}main.cppPCLQtViewer.cppPCLQtViewer.h
)target_link_libraries(${PROJECT_NAME}Qt5::QuickQt5::QuickControls2Qt5::3DCoreQt5::3DRenderQt5::3DInputQt5::3DExtras${PCL_LIBRARIES}
)

这种集成方式充分利用了PCL强大的点云处理能力和Qt/QML出色的UI/交互能力,可以构建出功能丰富、交互友好的点云处理应用程序。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mybatis plus打印sql日志到指定目录

1、mybatis plus打印sql日志 参考文档&#xff1a;mybatis plus打印sql日志_mybatisplus日志打印-CSDN博客 2、修改 修改InfoLevelLogger Override public void debug(String s) {// 修改这里logger.info(s);log.debug(s); } 增加&#xff1a;log.debug(s); 修改logback.x…

vue3 watch和watchEffect 的用法和区别

在 Vue 3 里&#xff0c;watch 和 watchEffect 都是用于响应式数据变化的 API&#xff0c;但它们在使用方法和应用场景上存在差异。下面详细介绍它们的用法和区别。 用法 watch watch 用于监听特定的响应式数据源&#xff0c;当数据源发生变化时&#xff0c;会执行相应的回调…

Qt中修改了UI设计文件后编译不生效问题的解决办法

复制工程过来后&#xff1a; 1、删除build文件 2、删除.user文件&#xff0c;恢复为文件最初的那样 3、执行make distclean,删除所有由先前构建过程生成的文件 4、再次打开工程&#xff0c;修改ui文件编译生效&#xff01;

EtherCAT转ProfiNet边缘计算网关配置优化:汽车制造场景下PLC与机器人协同作业案例

1.行业背景与需求分析 智能汽车焊装车间是汽车制造的核心工艺环节&#xff0c;某德国豪华品牌在其上海MEB工厂新建的焊装车间中&#xff0c;采用西门子S7-1500PLC作为ProfiNet主站&#xff0c;负责整线协调与质量追溯&#xff1b;同时部署KUKAKR1500Titan机器人&#xff08;Eth…

day46—双指针-两数之和-输入有序数组(LeetCode-167)

题目描述 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] &#xff0c;则 1 < index1 < index2 &l…

线性代数 | 知识点整理 Ref 1

注&#xff1a;本文为 “线性代数 | 知识点整理” 相关文章合辑。 因 csdn 篇幅合并超限分篇连载&#xff0c;本篇为 Ref 1。 略作重排&#xff0c;未整理去重。 图片清晰度限于引文原状。 如有内容异常&#xff0c;请看原文。 线性代数知识汇总 Arrow 于 2016-11-27 16:27:5…

比特币的跨输入签名聚合(Cross-Input Signature Aggregation,CISA)

1. 引言 2024 年&#xff0c;人权基金会&#xff08;Human Rights Foundation&#xff0c;简称 HRF&#xff09;启动了一项研究奖学金计划&#xff0c;旨在探讨“跨输入签名聚合”&#xff08;Cross-Input Signature Aggregation&#xff0c;简称 CISA&#xff09;的潜在影响。…

3.基础开发工具

1.软件包管理器 1.1什么是软件包 • 在Linux下安装软件, ⼀个通常的办法是下载到程序的源代码, 并进⾏编译, 得到可执⾏程序. • 但是这样太⿇烦了, 于是有些⼈把⼀些常⽤的软件提前编译好, 做成软件包(可以理解成windows上 的安装程序)放在⼀个服务器上, 通过包管理器可以很…

Golang errors 包快速上手

文章目录 1.变量2.类型3.函数3.1 New3.2 Is简介函数签名核心功能示例代码使用场景注意事项小结 3.3 As简介函数签名核心功能示例代码使用场景注意事项小结 3.4 Unwrap简介函数签名核心功能使用示例使用场景注意事项小结 3.5 Join简介函数签名核心功能使用场景注意事项小结 4.小…

Java File 类详解

Java File 类详解 File 类是 Java 中用于表示文件和目录路径名的抽象类&#xff0c;位于 java.io 包中。它提供了丰富的 API&#xff0c;用于操作文件系统&#xff0c;包括创建、删除、重命名、查询文件属性等功能。 1. File 类核心知识点 &#xff08;1&#xff09;构造方法…

基于javaweb的SpringBoot儿童爱心管理系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…

Unity Nav Mesh导航系统的简单使用

标题 1.下载。2.面板位置3.object面板4.Area面板5.Bake面板6.Agent面板7.Nav Mesh Agent组件8.Nav Mesh Obstacle组件9.简单使用 1.下载。 unity2022以上版本要去packageManager中下载。 2.面板位置 3.object面板 Navigation Static&#xff1a;设置该物体是否被列入静态寻路…

FairyGUI图标文字合批失败的原因

1&#xff09;FairyGUI图标文字合批失败的原因 2&#xff09;为什么Cubemap的内存占用超高 3&#xff09;如何找到网格某个切面的中心点 4&#xff09;为什么SafeZone在倒屏后方向相反 这是第428篇UWA技术知识分享的推送&#xff0c;精选了UWA社区的热门话题&#xff0c;涵盖了…

[BUG]Cursor C++扩展不支持

本文内容组织形式 问题描述失效原因解决方案使用野版C Extension 猜你喜欢结语 问题描述 日期&#xff1a;20250419 操作系统&#xff1a; mac C代码没有办法进行跳转&#xff0c;并且和以前的文本标亮也不同 并且还有如下问题弹窗 C/C 扩展只能与 Microsoft Visual Studio…

深⼊理解 JVM 执⾏引擎

深⼊理解 JVM 执⾏引擎 其中前端编译是在 JVM 虚拟机之外执⾏&#xff0c;所以与 JVM 虚拟机没有太⼤的关系。任何编程语⾔&#xff0c;只要能够编译出 满⾜ JVM 规范的 Class ⽂件&#xff0c;就可以提交到 JVM 虚拟机执⾏。⾄于编译的过程&#xff0c;如果你不是想要专⻔去研…

Ubuntu 部署 DeepSeek

在 Ubuntu 系统上部署 DeepSeek 模型&#xff0c;能让用户利用其强大的人工智能能力&#xff0c;同时保障数据的安全性与操作的自主性。不过&#xff0c;这一过程涉及诸多技术细节&#xff0c;需要谨慎操作。以下将为你详细介绍在 Ubuntu 系统部署 DeepSeek 的操作步骤及注意事…

通义灵码 Rules 库合集来了,覆盖Java、TypeScript、Python、Go、JavaScript 等

通义灵码新上的外挂 Project Rules 获得了开发者的一致好评&#xff1a;最小成本适配我的开发风格、相当把团队经验沉淀下来&#xff0c;是个很好功能…… 那么有哪些现成的 Rules 可以抄作业呢&#xff0c;今天我们官方输出了 Java、TypeScript、Python、Go、JavaScript 等语…

山东大学软件学院项目实训-基于大模型的模拟面试系统-Token过期重定向问题

项目结构 ├── assets/ # 静态资源&#xff08;CSS/图片&#xff09; ├── components/ # Vue 组件 ├── layouts/ # 布局模板 ├── pages/ # 自动生成路由 ├── plugins/ # 插件&#xff08;如 axios 拦截器&#xff09; …

SAP案例:珠海汉胜科技SAP S/4 HANA智能制造实践与价值实现

客户简介 珠海汉胜科技股份有限公司为高科技生产企业&#xff0c;成立于1985年&#xff0c;拥有员工近2000人。主要从事生产、销售、研发&#xff1a;光纤光缆、电线、电缆及附件、铝塑复合管&#xff1b;光纤光缆、电缆、电线生产项目的策划及技术咨询。它致力于为国内外无线电…

Spring Boot 项目中发布流式接口支持实时数据向客户端推送

1、pom依赖添加 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>2、事例代码 package com.pojo.prj.controller;import com.pojo.common.core.utils.String…