计算点云表面法线并可视化

#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/search/kdtree.h>
#include <pcl/features/normal_3d.h>
#include <boost/thread.hpp>  // For threading support


int main(int argc, char** argv)
{
    // 创建点云对象指针
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);

    // 加载点云文件
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("D:/py code/3.pcd", *cloud) != 0)
    {
        return -1;
    }

    // 创建法线估计对象
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation;
    normalEstimation.setInputCloud(cloud);
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
    normalEstimation.setSearchMethod(tree);
    normalEstimation.setKSearch(20);
    normalEstimation.compute(*normals);

    // 创建可视化对象
    pcl::visualization::PCLVisualizer viewer("Cloud Viewer");

    // 设置背景为黑色
    viewer.setBackgroundColor(0, 0, 0);

    // 添加点云
    viewer.addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");

   //对于封闭的、已知的几何体,设置视点是确保法线方向一致的一个有效方法。在PCL中,可以使用NormalEstimationsetViewPoint方法设置视点,默认视点是在坐标原点(0,0,0),对于许多情况可能不适用。对于斯坦福兔子模型,应该设置视点在模型外部的某个位置
    // 假设模型位于原点附近,可以将视点设置在Z轴的某个正值,设置包围盒中心例如(0, 0, 10) 确定法线向内还是向外


    normalEstimation.setViewPoint(0.16, 0.16, 0.12);

    // 输出法线数量
    std::cout << "Number of normals calculated: " << normals->size() << std::endl;


//尽管设置视点通常足以确保法线的正确方向,但有时还需要对每个法线向量进行检查和调整。可以编写一个函数,检查每个法线与从模型中心指向该点的向量之间的点积。如果点积为负,则表明法线指向内部,需要反转。
    Eigen::Vector4f centroid;
    pcl::compute3DCentroid(*cloud, centroid);

    for (size_t i = 0; i < normals->size(); ++i) {
        Eigen::Vector3f point(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z);
        Eigen::Vector3f normal(normals->points[i].normal_x, normals->points[i].normal_y, normals->points[i].normal_z);
        Eigen::Vector3f toPoint = point - centroid.head<3>();

        // 检查法线方向
        if (normal.dot(toPoint) < 0) {
            normals->points[i].normal_x *= -1;
            normals->points[i].normal_y *= -1;
            normals->points[i].normal_z *= -1;
        }
    }

    // 添加法线显示
    viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 50, 0.02, "normals");//参数 50 和 0.02 分别代表每50个点显示一个法线,每个法线的长度是0.02(这些参数可以根据需要调整以获得更好的视觉效果)
    viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0.0, 1.0, 0.0, "normals");
   

    // 设置点云颜色为青色
    viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
    viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 1.0, 1.0, "sample cloud");

    // 开启用户界面循环
    while (!viewer.wasStopped())
    {
        viewer.spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }

    return 0;
}

//结果如图

要读取点云文件,您可以使用PCL(Point Cloud Library)库。以下是一个简单的示例,演示如何读取点云文件、提取点云表面可视化点云。 ```c++ #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/features/normal_3d.h> #include <pcl/surface/gp3.h> #include <pcl/visualization/pcl_visualizer.h> int main(int argc, char** argv) { // 读取点云文件 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); if (pcl::io::loadPCDFile<pcl::PointXYZ>("D:/dm/py_pcd/volex_grid/1.pcd", *cloud) == -1) { std::cerr << "Cannot read file!" << std::endl; return -1; } // 计算点云法线 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; ne.setInputCloud(cloud); pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>); ne.setSearchMethod(tree); pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>); ne.setRadiusSearch(0.03); ne.compute(*cloud_normals); // 提取点云表面 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>); pcl::concatenateFields(*cloud, *cloud_normals, *cloud_with_normals); pcl::search::KdTree<pcl::PointNormal>::Ptr tree2(new pcl::search::KdTree<pcl::PointNormal>); tree2->setInputCloud(cloud_with_normals); pcl::GreedyProjectionTriangulation<pcl::PointNormal> gp3; pcl::PolygonMesh triangles; gp3.setSearchRadius(0.025); gp3.setMu(2.5); gp3.setMaximumNearestNeighbors(100); gp3.setMaximumSurfaceAngle(M_PI / 4); gp3.setMinimumAngle(M_PI / 18); gp3.setMaximumAngle(2 * M_PI / 3); gp3.setNormalConsistency(false); gp3.setInputCloud(cloud_with_normals); gp3.setSearchMethod(tree2); gp3.reconstruct(triangles); // 可视化点云 pcl::visualization::PCLVisualizer viewer("PointCloud Viewer"); viewer.setBackgroundColor(0, 0, 0); viewer.addPolygonMesh(triangles, "triangles"); viewer.addPointCloud<pcl::PointXYZ>(cloud, "cloud"); viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud"); while (!viewer.wasStopped()) { viewer.spinOnce(); } return 0; } ``` 这段代码首先使用`pcl::io::loadPCDFile`函数读取点云文件,然后使用`pcl::NormalEstimation`计算点云法线。接着,使用`pcl::GreedyProjectionTriangulation`提取点云表面,并将结果存储在`pcl::PolygonMesh`中。最后使用`pcl::visualization::PCLVisualizer`可视化点云。您可以根据需要更改算法的参数以获得更好的结果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值