VTK/PCL点云可视化:解决加载后需要手动缩放的问题

问题描述

我在使用VTK和PCL进行点云可视化时,遇到一个问题:我加载点云数据后,VTK界面没有显示点云数据,我需要缩放一下,才会显示出点云,我搜索了一下,说是相机初始化位置和角度的问题,但是我觉得如果你只是缩放一下就能看到,就不是相机视角的原因吧然后我缩放后能看到后,我又去加载了一些点,这时候,如果不缩放,还是继续看不到,缩放后才会看到,这个其实就很奇怪,我第二次加载的点就是第一次视角下附近的点,但是为啥不缩放也看不到,然后我问了ai,然后给了我回答。

根本原因分析

经过分析,问题的根本原因主要有以下几点:

  1. 相机初始化问题:VTK默认的相机位置和视角可能不适合当前点云的尺度
  2. 边界框计算缺失:没有自动计算点云的边界框,导致相机不知道点云的范围
  3. 多数据源问题 :当同时加载多个点云时,resetCamera()可能只考虑了部分点云

解决方案

针对以上问题,我们可以通过以下步骤解决:

1. 计算点云边界框

首先,我们需要计算点云的边界框,获取点云的最小和最大坐标值:

cpp 复制代码
// 计算点云边界框
pcl::PointXYZ minPt, maxPt;
pcl::getMinMax3D(*cloud, minPt, maxPt);

2. 计算中心点和尺度

根据边界框计算点云的中心点和整体尺度:

cpp 复制代码
// 计算中心点
double centerX = (minPt.x + maxPt.x) / 2.0;
double centerY = (minPt.y + maxPt.y) / 2.0;
double centerZ = (minPt.z + maxPt.z) / 2.0;

// 计算点云尺度(最大维度)
double size = std::max({maxPt.x - minPt.x, maxPt.y - minPt.y, maxPt.z - minPt.z});

3. 设置相机位置

根据计算得到的中心点和尺度,设置相机位置:

cpp 复制代码
// 设置相机位置:在点云中心的正上方,距离为尺度的2倍
view->setCameraPosition(centerX, centerY, centerZ + size * 2, 
                        centerX, centerY, centerZ, 0, 1, 0);

4. 重置相机

最后,调用resetCamera()确保所有点都在视野范围内:

cpp 复制代码
view->resetCamera();
ui.openGLWidget->update();

完整代码实现

1. 加载PCD文件时的处理

cpp 复制代码
void VTK930::onOpen() {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
        new pcl::PointCloud<pcl::PointXYZ>());
    QString fileName = QFileDialog::getOpenFileName(this,
        QStringLiteral("打开点云"), ".",
        QStringLiteral("PCD文件(*.pcd)"));
    if (fileName == "") return;
    pcl::io::loadPCDFile(fileName.toStdString(), *cloud);

    if (cloud->empty()) {
        QMessageBox::warning(this, QStringLiteral("警告"),
            QStringLiteral("点云文件为空!"));
        return;
    }

    view->removePointCloud("cloud");
    view->addPointCloud(cloud, "cloud");
    
    // 计算点云边界框并设置相机
    pcl::PointXYZ minPt, maxPt;
    pcl::getMinMax3D(*cloud, minPt, maxPt);
    double centerX = (minPt.x + maxPt.x) / 2.0;
    double centerY = (minPt.y + maxPt.y) / 2.0;
    double centerZ = (minPt.z + maxPt.z) / 2.0;
    double size = std::max({maxPt.x - minPt.x, maxPt.y - minPt.y, maxPt.z - minPt.z});
    
    view->setCameraPosition(centerX, centerY, centerZ + size * 2, centerX, centerY, centerZ, 0, 1, 0);
    view->resetCamera();
    ui.openGLWidget->update();
}

2. 添加点到可视化时的处理

cpp 复制代码
void VTK930::addPointsToVisualizer(const std::vector<Point3D>& points, int r, int g, int b, const std::string& groupName) {
    // ... 点云添加代码 ...

    view->removePointCloud(groupName);
    view->addPointCloud(cloud, groupName);
    view->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,
        (double)r / 255.0, (double)g / 255.0, (double)b / 255.0, groupName);

    // 计算所有点云的边界框并设置相机
    double minX = std::numeric_limits<double>::max(), minY = std::numeric_limits<double>::max(), minZ = std::numeric_limits<double>::max();
    double maxX = std::numeric_limits<double>::lowest(), maxY = std::numeric_limits<double>::lowest(), maxZ = std::numeric_limits<double>::lowest();
    bool hasPoints = false;
    
    for (const auto& pair : groupClouds) {
        if (!pair.second->empty()) {
            hasPoints = true;
            for (const auto& pt : pair.second->points) {
                minX = std::min(minX, (double)pt.x);
                minY = std::min(minY, (double)pt.y);
                minZ = std::min(minZ, (double)pt.z);
                maxX = std::max(maxX, (double)pt.x);
                maxY = std::max(maxY, (double)pt.y);
                maxZ = std::max(maxZ, (double)pt.z);
            }
        }
    }
    
    if (hasPoints) {
        double centerX = (minX + maxX) / 2.0;
        double centerY = (minY + maxY) / 2.0;
        double centerZ = (minZ + maxZ) / 2.0;
        double size = std::max({maxX - minX, maxY - minY, maxZ - minZ});
        
        view->setCameraPosition(centerX, centerY, centerZ + size * 2, centerX, centerY, centerZ, 0, 1, 0);
    }
    
    view->resetCamera();
    ui.openGLWidget->update();
}

结果

修改后的代码,确实没有之前的情况了。

上面的完整代码是我项目的代码,你需要按需修改。

相关推荐
unityのkiven2 小时前
如何通过DirectShow用C++实现PTZ相机的控制?
开发语言·c++·数码相机
实心儿儿2 小时前
C++ —— C++11
开发语言·c++
小辉同志2 小时前
17. 电话号码的字母组合
c++·算法·leetcode·深度优先
你撅嘴真丑2 小时前
和为给定数 与 最匹配的矩阵
c++·算法·矩阵
南境十里·墨染春水2 小时前
C++ 笔记:std::bind 函数模板详解
前端·c++·笔记
CoderCodingNo2 小时前
【GESP】C++五级练习题 luogu-P1303 A*B Problem | 高精度计算
数据结构·c++·算法
故事和你912 小时前
洛谷-算法1-1-模拟与高精度2
开发语言·数据结构·c++·算法·动态规划
B1acktion2 小时前
2.6.堆排序——从堆结构到 Top-K,一套思路贯穿排序与选择
数据结构·c++·算法·排序算法
雪可问春风2 小时前
insightface进行视频中人脸识别
c++·音视频