PCL 计算点云的主曲率

发布于:2024-10-09 ⋅ 阅读:(148) ⋅ 点赞:(0)

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1 法向量计算

2.1.2 主曲率计算

2.1.3 可视化函数

2.2完整代码

三、实现效果


PCL点云算法汇总及实战案例汇总的目录地址链接:

PCL点云算法与项目实战案例汇总(长期更新)


一、概述

        主曲率的计算是点云处理中重要的一步,用于理解点云局部表面几何结构的弯曲程度。主曲率的大小直接反映了表面在某点附近的变化趋势,较大的主曲率意味着表面弯曲剧烈,较小的主曲率则表示表面趋于平坦

1.1原理

        主曲率计算主要基于点云的法向量和协方差矩阵。通过在局部邻域内计算点云的法向量和曲率信息,我们可以提取出该点的最大曲率(主曲率)和最小曲率。主要公式如下:

1.2实现步骤

  1. 读取点云数据:加载点云数据进行处理。
  2. 法向量计算:计算点云中每个点的法向量,获取局部曲面的方向。
  3. 主曲率计算:使用法向量和点云计算主曲率,包括最大和最小曲率。
  4. 可视化:展示原始点云与主曲率。

1.3应用场景

  1. 三维重建:通过主曲率信息,可以更好地提取点云表面的特征点和曲率突变区域,便于构建高精度的三维模型。
  2. 表面特征提取:在物体识别中,局部的表面特征对识别起着重要作用,主曲率为提取这些特征提供了基础。
  3. 质量检测:在检测零件表面缺陷时,主曲率的变化可以帮助定位裂痕、凹陷等表面问题。
  4. 机器人路径规划:在机器人表面检测或抓取任务中,了解物体表面的几何特征有助于路径规划与任务执行。

二、代码实现

2.1关键函数

2.1.1 法向量计算

通过 pcl::NormalEstimation 对点云的法向量进行计算:

pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud(cloud);               // 设置输入点云
ne.setSearchMethod(tree);               // 设置搜索方法
ne.setRadiusSearch(0.03);               // 设置半径
ne.compute(*normals);                   // 计算法向量

2.1.2 主曲率计算

通过 pcl::PrincipalCurvaturesEstimation 计算主曲率:

pcl::PrincipalCurvaturesEstimation<pcl::PointXYZ, pcl::Normal, pcl::PrincipalCurvatures> pce;
pce.setInputCloud(cloud);               // 设置输入点云
pce.setInputNormals(normals);           // 设置法向量
pce.setSearchMethod(tree);              // 设置搜索方法
pce.setRadiusSearch(0.03);              // 设置搜索半径
pce.compute(*curvatures);               // 计算主曲率

2.1.3 可视化函数

通过 pcl::visualization::PCLVisualizer 可视化原始点云和法向量信息:

void visualizePointCloudAndCurvatures(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::Normal>::Ptr normals)
{
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Curvatures Viewer"));
    int vp_1, vp_2;
    viewer->createViewPort(0.0, 0.0, 0.5, 1.0, vp_1);   // 原始点云窗口
    viewer->setBackgroundColor(1.0, 1.0, 1.0, vp_1);
    viewer->addText("Original PointCloud", 10, 10, "vp1_text", vp_1);
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color_handler(cloud, 255, 0, 0); // 红色
    viewer->addPointCloud(cloud, cloud_color_handler, "original_cloud", vp_1);

    viewer->createViewPort(0.5, 0.0, 1.0, 1.0, vp_2);   // 法向量窗口
    viewer->setBackgroundColor(0.98, 0.98, 0.98, vp_2);
    viewer->addText("Normals", 10, 10, "vp2_text", vp_2);
    viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 10, 0.05, "normals", vp_2);

    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }
}

2.2完整代码

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/principal_curvatures.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>

using namespace std;

void visualizePointCloudAndCurvatures(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::Normal>::Ptr normals)
{
    // 创建PCL可视化器
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Curvatures Viewer"));

    // 创建视口1,显示原始点云
    int vp_1;
    viewer->createViewPort(0.0, 0.0, 0.5, 1.0, vp_1);
    viewer->setBackgroundColor(0.0, 0.0, 0.0, vp_1);  // 设置白色背景
    viewer->addText("Original PointCloud", 10, 10, "vp1_text", vp_1);
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color_handler(cloud, 255, 0, 0);  // 红色点云
    viewer->addPointCloud(cloud, cloud_color_handler, "original_cloud", vp_1);

    // 创建视口2,显示主曲率
    int vp_2;
    viewer->createViewPort(0.5, 0.0, 1.0, 1.0, vp_2);
    viewer->setBackgroundColor(0.01, 0.01, 0.01, vp_2);  // 设置浅灰色背景
    viewer->addText("Normals", 10, 10, "vp2_text", vp_2);
    viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 10, 0.05, "normals", vp_2);

    // 启动可视化循环
    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }
}

int main(int argc, char** argv)
{
    // 1. 读取点云数据
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile<pcl::PointXYZ>("bunny.pcd", *cloud);

    // 2. 创建用于计算法向量的对象
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);

    ne.setInputCloud(cloud);  // 设置输入点云
    ne.setSearchMethod(tree);  // 设置搜索方法
    ne.setRadiusSearch(0.03);  // 设置搜索半径
    ne.compute(*normals);  // 计算法向量

    // 3. 创建用于计算主曲率的对象
    pcl::PrincipalCurvaturesEstimation<pcl::PointXYZ, pcl::Normal, pcl::PrincipalCurvatures> pce;
    pcl::PointCloud<pcl::PrincipalCurvatures>::Ptr curvatures(new pcl::PointCloud<pcl::PrincipalCurvatures>);
    pce.setInputCloud(cloud);     // 设置输入点云
    pce.setInputNormals(normals); // 设置法向量
    pce.setSearchMethod(tree);    // 设置搜索方法
    pce.setRadiusSearch(0.03);    // 设置搜索半径
    pce.compute(*curvatures);     // 计算主曲率

    // 4. 可视化原始点云与法向量
    visualizePointCloudAndCurvatures(cloud, normals);

    return 0;
}

三、实现效果