PCL 第四讲-PCL-点云可视化

文章目录

简介和函数说明

PCL(Point Cloud Library)的可视化模块主要提供两个核心类:CloudViewer (简单快速)和 PCLVisualizer (功能强大)。此外,还提供了直方图可视化、深度图像可视化以及一个命令行工具 pcl_viewer

下表整理了所有主要可视化函数和方法的详细说明:

类/模块 函数/方法 描述 关键参数/特性
CloudViewer CloudViewer (string window_name) 构造函数,创建一个简单的可视化窗口。 window_name:窗口名称
showCloud (cloud) 在窗口中显示点云。该函数是同步的,执行后会等待渲染完成。 cloud:要显示的点云指针
runOnVisualizationThread (callback) 注册一个回调函数,该函数在每帧渲染时都会被调用,用于执行自定义绘制或更新。 callback:回调函数,接受PCLVisualizer引用
runOnVisualizationThreadOnce (callback) 注册一个回调函数,该函数在可视化线程中仅被执行一次,常用于初始化设置。 callback:一次性回调函数
wasStopped () 检查窗口是否已经被用户关闭。 返回 bool
PCLVisualizer PCLVisualizer::Ptr (string window_name) 构造函数,创建一个功能完备的可视化对象(通常使用智能指针)。 window_name:窗口名称
addPointCloud (cloud, ...) 将点云添加到视窗中。可以配合颜色处理器(PointCloudColorHandler)实现不同着色。 cloud, color_handler, id
setBackgroundColor (r, g, b) 设置视窗的背景颜色。 r, g, b:0-1或0-255的颜色值
addCoordinateSystem (scale) 在视窗中添加一个表示坐标轴的3D坐标系。 scale:坐标轴的大小
initCameraParameters () 初始化相机参数,以便更好地适应场景。
addSphere (center, radius, ...) 在指定位置添加一个球体。 center, radius, id
addLine (point1, point2, ...) 在两点之间添加一条线段。 point1, point2, id
addPlane (coefficients, id) 根据模型系数添加一个平面。 coefficients, id
addCone (coefficients, id) 根据模型系数添加一个圆锥体。 coefficients, id
addPointCloudNormals (cloud, normals, ...) 同时显示点云及其法线。 cloud, normals, level, scale
setPointCloudRenderingProperties (...) 设置点云的渲染属性,如点的大小、透明度等。 property, value, id
createViewPort (xmin, ymin, xmax, ymax, viewport_id) 在窗口中创建多个独立的视口,用于显示不同数据。 归一化坐标 [0,1], viewport_id
spin () / spinOnce () spin()进入事件循环直到窗口关闭;spinOnce()处理一次事件后返回。
PCLHistogramVisualizer addHistogramData (data, bins, ...) 添加并显示一维数据的直方图。 data, bins
view () 显示直方图窗口。
RangeImageVisualizer showRangeImage (range_image) 显示深度图像(Range Image)。 range_image:输入的深度图像
命令行工具 pcl_viewer <file_name.pcd> [options] 一个独立的命令行程序,用于快速查看PCD文件。 -bc r,g,b背景色, -ps X点大小等

说明CloudViewerPCLVisualizer 的一个轻量级封装,使用更简单但不能用于多线程。如果你的需求超过简单的显示(如绘制法线、形状或多视口),推荐直接使用功能更强大的 PCLVisualizer。所有高级渲染功能都依赖于VTK(Visualization Toolkit)库。

PCL 点云可视化核心原理

PCL 可视化的核心是基于 VTK(Visualization Toolkit)图形库实现的三维渲染与交互,本质是将点云的三维坐标、颜色、法向量等数据,通过 VTK 的渲染管线转化为屏幕上的可视化图像,同时支持鼠标 / 键盘交互操作。

核心渲染流程

数据封装

将 PCL 点云(PointCloud)转换为 VTK 可识别的多边形数据(vtkPolyData),包含点坐标、颜色、法向量等属性。

渲染管道

VTK 通过 "数据源→映射器(Mapper)→演员(Actor)→渲染器(Renderer)→渲染窗口(RenderWindow)→交互器(Interactor)" 的管线,完成数据到图像的转化。

  • 映射器(Mapper):负责将点云数据转换为图形基元(点、线、面)。
  • 演员(Actor):承载图形基元,控制显示属性(颜色、大小、透明度)。
  • 渲染器(Renderer):管理场景中的所有演员,设置背景、视角。
  • 渲染窗口(RenderWindow):承载渲染器,作为显示载体。
  • 交互器(Interactor):处理鼠标、键盘事件,实现旋转、平移、缩放等交互。

交互渲染

启动交互循环,实时响应用户操作,动态更新渲染画面

PCL可视化核心知识点

核心可视化类

PCL 对 VTK 进行了封装,提供了更简洁的可视化接口,核心类如下:

  • pcl::visualization::PCLVisualizer
    最通用的可视化类,支持单 / 多窗口、点云 / 形状 / 文本渲染、自定义交互
  • pcl::visualization::CloudViewer
    简化版可视化类,仅支持单窗口点云显示,接口极简
  • pcl::visualization::RangeImageVisualizer
    专门用于深度图 /range image 可视化

点云显示配置知识点

点云显示属性

  • 点大小通过setPointCloudRenderingProperties设置,控制点的渲染尺寸(值越大点越粗)。
  • 点颜色:支持单色渲染、按坐标 / 强度 / 标签着色、RGB 彩色点云直接显示。
  • 设置点云的透明程度,用于多层点云叠加显示。
  • 渲染模式:支持点渲染(默认)、线框渲染、面渲染(适用于有序点云 / 网格)。

窗体与视图配置

  • 单窗口 / 多窗口:createViewPort创建子视图,实现多窗口并排显示(对比不同点云)。
  • 背景色:setBackgroundColor设置窗口背景(默认黑色,可改为白色 / 灰色)
  • 窗口标题 / 大小:初始化时设置窗口名称,setSize控制窗口像素尺寸。
  • 相机视角:setCameraPosition设置初始观察视角,resetCamera重置视角。

文字标注

  • 文本标注:addText添加静态文本,addText3D添加 3D 空间文本(随视角移动)。
  • 几何形状:addSphere/addCube/addLine/addArrow添加球体、立方体、线段、箭头,用于标注关键点、法向量、边界框。
  • 坐标系统:addCoordinateSystem添加世界坐标系(红 X、绿 Y、蓝 Z),辅助空间定位。

交互操作知识点

默认交互快捷键

  • 旋转视图 鼠标左键拖动
  • 平移视图 鼠标右键拖动
  • 缩放视图 鼠标滚轮滚动
  • 重置视角 按R键
  • 显示 / 隐藏坐标轴 按C键
  • 截图保存 按P键
  • 退出可视化 按Q键

自定义交互事件

通过registerKeyboardCallback/registerPointPickingCallback注册回调函数,实现自定义键盘事件、点拾取事件(如点击点云输出坐标、选中点高亮)

特殊点云可视化

  • 彩色点云:直接加载PointXYZRGB类型点云,无需额外配置即可显示 RGB 颜色。
  • 法向量可视化:addPointCloudNormals渲染点云法向量(箭头表示方向,可设置箭头长度 / 密度)。
  • 关键点可视化:通过setPointCloudRenderingProperties将关键点设为不同颜色 / 大小,突出显示。
  • 网格 / 曲面可视化:支持PolygonMesh类型数据,渲染点云重构后的曲面。

可视化优化知识点

  • 多线程渲染:CloudViewer默认多线程,PCLVisualizer需手动处理(避免主线程阻塞)。
  • 点云更新:updatePointCloud动态更新点云数据(无需重新创建可视化对象,适用于实时点云)。
  • 性能优化:大规模点云可先降采样(VoxelGrid)再可视化,减少渲染压力;关闭不必要的标注 / 形状,提升帧率。

PCL 可视化完整代码示例

基础点云可视化(CloudViewer 快速预览)

cpp 复制代码
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/cloud_viewer.h>
#include <iostream>

// 点云类型定义(XYZ+RGB彩色点云)
using PointT = pcl::PointXYZRGB;

int main() {
    // 1. 加载点云(也可模拟生成随机点云)
    pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
    // 方式1:加载本地PCD文件
    if (pcl::io::loadPCDFile<PointT>("cloud.pcd", *cloud) == -1) {
        // 若加载失败,模拟生成1000个彩色随机点
        cloud->width = 1000;
        cloud->height = 1;
        cloud->points.resize(cloud->width * cloud->height);
        for (auto& point : cloud->points) {
            point.x = rand() % 100;
            point.y = rand() % 100;
            point.z = rand() % 100;
            point.r = rand() % 256;  // 随机红色通道
            point.g = rand() % 256;  // 随机绿色通道
            point.b = rand() % 256;  // 随机蓝色通道
        }
        std::cout << "未找到cloud.pcd,已生成随机彩色点云" << std::endl;
    }

    // 2. 创建CloudViewer可视化对象
    pcl::visualization::CloudViewer viewer("基础点云可视化");

    // 3. 显示点云
    viewer.showCloud(cloud);

    // 4. 等待窗口关闭(阻塞主线程)
    while (!viewer.wasStopped()) {
        // 可在此处添加实时更新逻辑
    }

    return 0;
}

高级可视化(PCLVisualizer 多窗口、标注、法向量、交互)

cpp 复制代码
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/features/normal_3d.h>
#include <pcl/filters/voxel_grid.h>
#include <iostream>
#include <thread>

using PointT = pcl::PointXYZRGB;
using NormalT = pcl::Normal;

// 自定义键盘交互回调函数


void keyboardEventOccurred(const pcl::visualization::KeyboardEvent& event, void* nothing) {
    if (event.getKeySym() == "h" && event.keyDown()) {
        std::cout << "===== 帮助信息 =====" << std::endl;
        std::cout << "鼠标左键:旋转视图" << std::endl;
        std::cout << "鼠标右键:平移视图" << std::endl;
        std::cout << "滚轮:缩放视图" << std::endl;
        std::cout << "R键:重置视角" << std::endl;
        std::cout << "P键:截图保存" << std::endl;
        std::cout << "Q键:退出可视化" << std::endl;
        std::cout << "H键:显示帮助" << std::endl;
    }
}

// 自定义点拾取回调函数
void pointPickingEventOccurred(const pcl::visualization::PointPickingEvent& event, void* viewer_void) {
    if (event.getPointIndex() == -1) return;
    float x, y, z;
    event.getPoint(x, y, z);
    std::cout << "选中点坐标:(" << x << ", " << y << ", " << z << ")" << std::endl;
}

int main() {
    // 1. 加载并预处理点云(降采样+法向量估计)
    pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
    pcl::PointCloud<PointT>::Ptr cloud_filtered(new pcl::PointCloud<PointT>);
    pcl::PointCloud<NormalT>::Ptr cloud_normals(new pcl::PointCloud<NormalT>);

    // 加载点云(失败则生成随机点)
    if (pcl::io::loadPCDFile<PointT>("cloud.pcd", *cloud) == -1) {
        cloud->width = 2000;
        cloud->height = 1;
        cloud->points.resize(cloud->width * cloud->height);
        for (auto& point : cloud->points) {
            point.x = rand() % 100;
            point.y = rand() % 100;
            point.z = rand() % 100;
            point.r = rand() % 256;
            point.g = rand() % 256;
            point.b = rand() % 256;
        }
    }

    // 降采样(优化可视化性能)
    pcl::VoxelGrid<PointT> vg;
    vg.setInputCloud(cloud);
    vg.setLeafSize(1.0f, 1.0f, 1.0f);  // 体素大小1m
    vg.filter(*cloud_filtered);
    std::cout << "原始点云数量:" << cloud->size() << ",降采样后:" << cloud_filtered->size() << std::endl;

    // 估计法向量(用于法向量可视化)
    pcl::NormalEstimation<PointT, NormalT> ne;
    ne.setInputCloud(cloud_filtered);
    pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>);
    ne.setSearchMethod(tree);
    ne.setRadiusSearch(3.0f);  // 邻域半径3m
    ne.compute(*cloud_normals);

    // 2. 创建PCLVisualizer对象
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("高级点云可视化"));
    viewer->setBackgroundColor(0.0, 0.0, 0.0);  // 黑色背景
    viewer->setWindowName("PCL高级可视化示例");
    viewer->setSize(1200, 600);  // 窗口尺寸1200x600

    // 3. 创建双窗口(左:原始点云+标注,右:降采样点云+法向量)
    int v1(0), v2(0);
    viewer->createViewPort(0.0, 0.0, 0.5, 1.0, v1);  // 左窗口(x0,y0,x1,y1)
    viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);  // 右窗口
    viewer->setViewPortName("原始点云+标注", v1);
    viewer->setViewPortName("降采样点云+法向量", v2);

    // 4. 左窗口:显示原始点云+文本+坐标系+线段
    viewer->addPointCloud(cloud, "original_cloud", v1);
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "original_cloud");  // 点大小2
    viewer->addText("原始点云(1000个点)", 10, 10, 16, 1.0, 1.0, 1.0, "original_text", v1);  // 白色文本
    viewer->addCoordinateSystem(50.0, "original_coord", v1);  // 坐标系(尺寸50)
    viewer->addLine(cloud->points[0], cloud->points[1], 1.0, 0.0, 0.0, "line1", v1);  // 红色线段(连接前两个点)

    // 5. 右窗口:显示降采样点云+法向量+球体标注
    viewer->addPointCloud(cloud_filtered, "filtered_cloud", v2);
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "filtered_cloud");  // 点大小3
    viewer->addPointCloudNormals<PointT, NormalT>(cloud_filtered, cloud_normals, 10, 2.0f, "normals", v2);  // 法向量(每10个点显示1个,箭头长2)
    viewer->addSphere(cloud_filtered->points[0], 5.0f, 0.0, 1.0, 0.0, "sphere1", v2);  // 绿色球体(标注第一个点)
    viewer->addText("降采样点云+法向量", 10, 10, 16, 0.0, 1.0, 0.0, "filtered_text", v2);  // 绿色文本

    // 6. 注册自定义交互事件
    viewer->registerKeyboardCallback(keyboardEventOccurred, (void*)nullptr);  // 键盘事件
    viewer->registerPointPickingCallback(pointPickingEventOccurred, (void*)viewer.get());  // 点拾取事件

    // 7. 启动可视化循环(非阻塞,用spinOnce+sleep)
    while (!viewer->wasStopped()) {
        viewer->spinOnce(100);  // 每100ms刷新一次
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    return 0;
}
相关推荐
格林威2 小时前
Baumer相机镜面反射区域遮蔽重建:恢复缺失纹理的 6 个关键技术,附 OpenCV+Halcon 实战代码!
人工智能·opencv·计算机视觉·视觉检测·工业相机·智能相机·堡盟相机
啊阿狸不会拉杆2 小时前
《计算机视觉:模型、学习和推理》第 11 章-链式模型和树模型
人工智能·学习·算法·机器学习·计算机视觉·hmm·链式模型
椒颜皮皮虾྅2 小时前
OpenVINO C# API 中文README.md
人工智能·深度学习·目标检测·计算机视觉·c#·边缘计算·openvino
有为少年2 小时前
Monarch矩阵:从设计直觉到数学推导与实际应用
人工智能·深度学习·学习·线性代数·机器学习·计算机视觉·矩阵
吾在学习路19 小时前
SAMCT: Segment Any CT Allowing Labor-Free Task-Indicator Prompts
深度学习·计算机视觉
I Promise3421 小时前
BEV视角智驾方案业务需求分类与主流技术全解
人工智能·深度学习·计算机视觉
Humbunklung1 天前
深入解析PPTX:编程实现批量字体替换的原理与实践
人工智能·python·计算机视觉·manus
啊阿狸不会拉杆1 天前
《计算机视觉:模型、学习和推理》第 8 章-回归模型
人工智能·python·学习·机器学习·计算机视觉·回归·回归模型
咚咚王者1 天前
人工智能之视觉领域 计算机视觉 第十四章 人脸检测
人工智能·计算机视觉