使用 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. 性能优化建议
-
点云分块加载:对于大型点云,实现分块加载机制
-
LOD(细节层次):根据视点距离动态调整显示细节
-
后台处理:将PCL处理任务放在后台线程
-
GPU加速:使用计算着色器处理点云数据
-
空间索引:使用八叉树等结构加速空间查询
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/交互能力,可以构建出功能丰富、交互友好的点云处理应用程序。
相关文章:
使用 PCL 和 Qt 实现点云可视化与交互
下面我将介绍如何结合点云库(PCL)和Qt框架(特别是QML)来实现点云的可视化与交互功能,包括高亮选择等效果。 1. 基本架构设计 首先需要建立一个结合PCL和Qt的基本架构: // PCLQtViewer.h #pragma once#include <QObject> #include <pcl/point…...
静态网页的开发
文章目录 基于 idea 开发静态网页添加web框架前端配置服务器并启动服务资源名字不是 index 静态网页 流转 基于 idea 开发静态网页 添加web框架 方法1 方法2 前端 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&quo…...
【CPU】结合RISC-V CPU架构回答中断系统的7个问题(个人草稿)
结合RISC-V CPU架构对中断系统七个关键问题的详细解析,按照由浅入深的结构进行说明: 一、中断请求机制(问题①) 硬件基础: RISC-V通过CLINT(Core Local Interrupter)和PLIC(Platfor…...
uCOS3实时操作系统(任务切换和任务API函数)
文章目录 任务切换任务API函数 任务切换 C/OS-III 将 PendSV 的中断优先级配置为最低的中断优先级,这么一来, PendSV 异常的中断服务函数就会在其他所有中断处理完成后才被执行。C/OS-III 就是将任务切换的过程放到 PendSV 异常的中断服务函数中处理的。…...
【Python网络爬虫开发】从基础到实战的完整指南
目录 前言:技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解核心作用讲解关键技术模块技术选型对比 二、实战演示环境配置要求核心代码实现(10个案例)案例1:基础静态页面抓取案例2:动…...
科学养生指南:解锁健康生活新方式
在快节奏的现代生活中,健康养生已成为人们关注的焦点。科学合理的养生方式,能帮助我们增强体质、预防疾病,享受更优质的生活。 饮食是健康养生的基石。遵循 “均衡饮食” 原则,每日饮食需包含谷类、蔬菜水果、优质蛋白质和健康…...
第十四届蓝桥杯 2023 C/C++组 有奖问答
目录 题目: 题目描述: 题目链接: 思路: 核心思路: 思路详解: 代码: 代码详解: 题目: 题目描述: 题目链接: 蓝桥云课 有奖问答 思路&…...
解决Chrome浏览器访问https提示“您的连接不是私密连接”的问题
如何绕过Chrome的“您的连接不是私密连接”证书警告页面 在使用Chrome浏览器访问一些自签名或测试用的HTTPS网站时,常常会遇到这样一个拦截页面: “您的连接不是私密连接” 虽然这是Chrome出于安全考虑的设计,但对于开发者或测试人员来说&am…...
transformer注意力机制
单头注意力机制 import torch import torch.nn.functional as Fdef scaled_dot_product_attention(Q, K, V):# Q: (batch_size, seq_len, d_k)# K: (batch_size, seq_len, d_k)# V: (batch_size, seq_len, d_v)batch_size: 一次输入的句子数。 seq_len: 每个句子的词数。 d_mo…...
QT 5.15 程序打包
说明: windeployqt 是 Qt 提供的一个工具,用于自动收集并复制运行 Qt 应用程序所需的动态链接库(.dll 文件)及其他资源(如插件、QML 模块等)到可执行文件所在的目录。这样你就可以将应用程序和这些依赖项一…...
秒杀抢购系统架构与优化全解:从业务特性到技术落地
一、秒杀抢购业务的本质 秒杀,顾名思义,就是“以秒为单位”的限时限量抢购活动。它的核心是短时间内聚集高流量,以超低价格进行引流。 这种业务场景对系统架构提出了极高的要求,主要表现为: 高并发访问量 极短的处理…...
【路由交换方向IE认证】BGP选路原则之AS-Path属性
文章目录 一、路由器BGP路由的处理过程控制平面和转发平面选路工具 二、BGP的选路顺序选路的前提选路顺序 三、AS-Path属性选路原则AS-Path属性特性AS-Path管进还是管出呢?使用AS-Path对进本AS的路由进行选路验证AS-Path不接收带本AS号的路由 四、BGP邻居建立配置 一…...
Spark-SQL与Hive
Spark-SQL与Hive的那些事儿:从连接到数据处理 在大数据处理领域,Spark-SQL和Hive都是非常重要的工具。今天咱们就来聊聊它们之间的关系,以及怎么用Spark-SQL去连接Hive进行数据处理。先说说Hive,它是Hadoop上的SQL引擎࿰…...
Linux系统下docker 安装 redis
docker安装最新版的redis 一、docker拉取最新版redis镜像 拉取镜像若没有指定版本,代表拉取最新版本 二、查询redis镜像 三、挂载配置文件 在docker容器内修改redis配置文件不方便,所以挂载配置文件,这样可以在外边修改redis配置 3.1 创建…...
【阿里云大模型高级工程师ACP习题集】2.1 用大模型构建新人答疑机器人
练习题 【单选题】1. 在调用通义千问大模型时,将API Key存储在环境变量中的主要目的是? A. 方便在代码中引用 B. 提高API调用的速度 C. 增强API Key的安全性 D. 符合阿里云的规定 【多选题】2. 以下哪些属于大模型在问答场景中的工作阶段?( ) A. 输入文本分词化 B. Toke…...
深度学习框架PyTorch——从入门到精通(3.3)YouTube系列——自动求导基础
这部分是 PyTorch介绍——YouTube系列的内容,每一节都对应一个youtube视频。(可能跟之前的有一定的重复) 我们需要Autograd做什么?一个简单示例训练中的自动求导开启和关闭自动求导自动求导与原地操作 自动求导分析器高级主题&…...
【基础算法】二分算法详解
🎯 前言:二分不是找某个数,而是找一个满足条件的位置/值 所以最关键的是:找到单调性,写好 check() 函数,剩下交给模板! 什么是二分算法 二分算法是一种在有序区间中查找答案的方法,时间复杂度:O(log n)。核心思想是: 每次把搜索区间分成两半,只保留可能存在答案的…...
mysql——基础知识
关键字大小写不敏感 查看表结构中的 desc describe 描述 降序中的 desc descend 1. 数据库的操作 1. 创建数据库 create database 数据库名;为防止创建的数据库重复 CREATE DATABASE IF NOT EXISTS 数据库名;手动设置数据库采用的字符集 character set 字符集名;chars…...
html+js+clickhouse环境搭建
实验背景: 我目前有一台服务器A,和一台主机B,两台设备属于同一局域网,相互之间可以通讯。服务器A中部署着clickhouse,我在主机B中想直接通过javascript代码访问服务器中的clickhouse数据库并获取数据。 ClickHouse 服务…...
JWT算法详解
JWT(JSON Web Token)的整个算法流程主要基于其签名算法。以最常见的签名算法HS256(HMAC SHA256)为例,以下是详细的算法流程,涵盖编码、签名和验证过程: 编码 构造头部(Header&#x…...
OOA-CNN-LSTM-Attention、CNN-LSTM-Attention、OOA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比
OOA-CNN-LSTM-Attention、CNN-LSTM-Attention、OOA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比 目录 OOA-CNN-LSTM-Attention、CNN-LSTM-Attention、OOA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比预测效果基本介绍程序设计参考资料 预测效果 基本介绍 基于OOA-CN…...
Python Cookbook-6.6 在代理中托管特殊方法
任务 在新风格对象模型中,Python 操作其实是在类中查找特殊方法的(而不是在实例中那是经典对象模型的处理方式)。现在,需要将一些新风格的实例包装到代理类中,此代理可以选择将一些特殊方法委托给内部的被包装对象。 解决方案 你需要即时地…...
PCIE Spec ---Base Address Registers
7.5.1.2.1 Base Address Registers (Offset 10h - 24h) 在 boot 到操作系统之前,系统软件需要生产一个内存映射的 address map ,用于告诉系统有多少内存资源,以及相应功能需要的内存空间,所以在设备的 PCI 内存空间中就有了这个 …...
Spring如何通过XML注册Bean
在上一篇当中我们完成了对三种资源文件的读写 上篇内容:Spring是如何实现资源文件的加载 Test public void testClassPathResource() throws IOException { DefaultResourceLoader defaultResourceLoader new DefaultResourceLoader(); Resource resource …...
理解 `#pragma pack`:C/C++内存对齐的钥匙
引言:为什么我的网络程序收发的数据总是错位? 在网络编程中,你是否遇到过这样的困惑:明明发送方和接收方的结构体定义完全一样,但解析出来的数据却乱七八糟?这很可能是因为内存对齐在作祟。今天我们就来深…...
开源键鼠共享软件的“爱恨情仇“:Deskflow、InputLeap与Barrier的演化史
开源键鼠共享软件的"爱恨情仇":Deskflow、InputLeap与Barrier的演化史 一、血脉渊源:从Synergy到三足鼎立 这三款软件的起源都与 Synergy 这款商业软件密切相关: 2001年:Synergy开创软件化KVM先河2017年&…...
【Python核心库实战指南】从数据处理到Web开发
目录 前言:技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解核心作用讲解关键技术模块对比 二、实战演示环境配置要求核心代码实现(5个案例)案例1:NumPy数组运算案例2:Pandas数据分析…...
运维:概念、模式与硬件基础
一、运维概述:从网管到智能运维的进化之路 1. 运维岗位的定义 IT运维管理是保障企业IT系统及网络可用性、安全性、稳定性,确保业务连续性的核心工作。通过专业技术手段,对计算机网络、应用系统、电信网络、软硬件环境及运维服务流程等进行综…...
基于Java的不固定长度字符集在指定宽度和自适应模型下图片绘制生成实战
目录 前言 一、需求介绍 1、指定宽度生成 2、指定列自适应生成 二、Java生成实现 1、公共方法 2、指定宽度生成 3、指定列自适应生成 三、总结 前言 在当今数字化与信息化飞速发展的时代,图像的生成与处理技术正日益成为众多领域关注的焦点。从创意设计到数…...
【版本控制】idea中使用git
大家好,我是jstart千语。接下来继续对git的内容进行讲解。也是在开发中最常使用,最重要的部分,在idea中操作git。目录在右侧哦。 如果需要git命令的详解: 【版本控制】git命令使用大全-CSDN博客 一、配置git 要先关闭项目…...
