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();
}

结果

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

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

相关推荐
re林檎2 分钟前
八大排序算法(C++实现)
c++·算法·排序算法
此生只爱蛋3 分钟前
【vscode环境配置心得】C++版
c++·ide·vscode
记录无知岁月9 分钟前
【C/C++】头文件包含问题分析
c语言·开发语言·c++
楚Y6同学10 分钟前
QT C++之保存界面设置为配置文件
c++·qt·保存配置
谭欣辰29 分钟前
C++ 堆 的基础与 二叉堆详解
开发语言·c++
ian4u35 分钟前
车载 Android C++ 完整技能路线:从基础到进阶
android·开发语言·c++
郝学胜-神的一滴36 分钟前
[力扣 227] 双栈妙解表达式计算:从思维逻辑到C++实战,吃透反向波兰式底层原理
java·前端·数据结构·c++·算法
Yuk丶1 小时前
Procedural Dialogue Engine - UE4程序化对话系统的技术实现
c++·游戏引擎·ue4·游戏程序·虚幻
自信150413057591 小时前
重生之从0开始学习c++之string(上)
开发语言·c++·学习
BestOrNothing_20151 小时前
C++零基础到工程实战(4.3.8):基于 vector 实现一个简易缓存数据库
c++·vector·string·缓存数据库·stringstream·键值存储·getline