PCL提取建筑物的平面

//ComputeBuildingNormals
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/surface/mls.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/gp3.h>
#include <pcl/ModelCoefficients.h>//模型系数头文件
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>//基于采样一致性分割的类的头文件


#include <pcl/filters/extract_indices.h>
//pcl::ModelCoefficients::Ptr cofficients (new pcl::ModelCoefficients);//模型系数
//pcl::PointIndices::Ptr inliers(new pcl::PointIndices);

using namespace std;

typedef pcl::PointXYZ PointT;

void SegBuilding(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in,string filename);//定义一个函数,对输入点云进行分割

int
main (int argc, char** argv)
{
    if(argc<2){
        cout<<"Error!"<<endl;
        return -1;
    }
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile(argv[1],*cloud_in);
    std::cout<<"cloud_in: "<<cloud_in->size()<<endl;
    std::cout<<"fileds: "<<pcl::getFieldsList(*cloud_in)<<std::endl;


    // 对点云重采样
    pcl::search::KdTree<PointT>::Ptr treeSampling (new pcl::search::KdTree<PointT>);
    pcl::PointCloud<PointT> mls_point;
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_smoothed;
    pcl::MovingLeastSquares<PointT,PointT> mls;
    mls.setComputeNormals(false);
    mls.setInputCloud(cloud_in);
    mls.setPolynomialOrder(2);
    mls.setPolynomialFit(false);
    mls.setSearchMethod(treeSampling);
    mls.setSearchRadius(0.05);
    mls.process(mls_point);

    // 输出重采样结果
    cloud_smoothed = mls_point.makeShared();

    ostringstream oss;
    oss<<"Smoothed_"<<argv[1];
    std::cout<<oss.str()<<"  |size: "<<cloud_smoothed->size() <<std::endl;
    std::cout<<oss.str()<<"  |fields: "<<pcl::getFieldsList(mls_point)<<std::endl;

    //save cloud_smoothed
    pcl::io::savePCDFileASCII(oss.str(),*cloud_smoothed);



    // 法线估计
    pcl::NormalEstimation<pcl::PointXYZ,pcl::Normal> normalEstimation;
    normalEstimation.setInputCloud(cloud_smoothed);
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
    normalEstimation.setSearchMethod(tree);
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
    normalEstimation.setKSearch(10);
    normalEstimation.compute(*normals);
    std::cout<<"normals: "<<normals->size()<<"\n"<<"normals fields: "<<pcl::getFieldsList(*normals)<<std::endl;
    oss.str("");
    oss<<"NormalsOnly_"<<argv[1];
    pcl::io::savePCDFileASCII(oss.str(),*normals);
//    //Triangle Projection
//    pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);
//    pcl::concatenateFields(*cloud_smoothed,*normals,*cloud_with_normals);
//    std::cout<<"cloud_with_normals fields: "<<pcl::getFieldsList(*cloud_with_normals)<<std::endl;
//    oss.str("");
//    oss<<"Normals_"<<argv[1];
//    pcl::io::savePCDFileASCII(oss.str(),*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.1);
//    gp3.setMu(2.5);
//    gp3.setMaximumNearestNeighbors(52);
//
//    gp3.setMaximumAngle(2*M_PI/3);
//    gp3.setMinimumAngle(M_PI/18);
//
//    gp3.setMaximumSurfaceAngle(M_PI/4);
//    gp3.setNormalConsistency(false);
//
//    gp3.setInputCloud(cloud_with_normals);
//    gp3.setSearchMethod(tree2);
//    gp3.reconstruct(triangles);



    //可视化
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer);
    int v4(0);
    viewer->setBackgroundColor(0,0,0,v4);
//    viewer->addPolylineFromPolygonMesh(triangles,"GPTriangle");
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color2(cloud_smoothed, 0,200,0);

    //平面分割
    SegBuilding(cloud_smoothed,argv[1]);//
    cout<<"Final cloud_smoothed: "<<cloud_smoothed->size()<<endl;

    //保存最后的剩下的点云
    oss.str("");
    oss<<"Remain_"<<argv[1];

    pcl::io::savePCDFileASCII(oss.str(),*cloud_smoothed);
    cout<<oss.str()<<" Saved!"<<endl;
//    viewer->addText("cloud_filtered_out",0,0,"cloud_filtered_out",v4);

    //viewer->addCoordinateSystem();
    viewer->spin();


    return 0;
}

void SegBuilding(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in, string filename) {

    cout<<"\nSegBuilding\n------------------------------------------------------"<<endl;
    pcl::PCDWriter writer;
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_p(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_f(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
    pcl::PointIndices::Ptr inliers(new pcl::PointIndices());  //创建一个PointIndices结构体指针
    // 创建分割对象
    pcl::SACSegmentation<pcl::PointXYZ> seg;
    // 可选
    seg.setOptimizeCoefficients(true); //设置对估计的模型做优化处理
    // 必选
    seg.setModelType(pcl::SACMODEL_PLANE);//设置分割模型类别
    seg.setMethodType(pcl::SAC_RANSAC);//设置使用那个随机参数估计方法
    seg.setMaxIterations(1000);//迭代次数
    seg.setDistanceThreshold(0.045);//设置是否为模型内点的距离阈值
    // 创建滤波器对象
    pcl::ExtractIndices<pcl::PointXYZ> extract;
    int i = 0, nr_points = (int) cloud_in->points.size();
    cout << "All Point: " << cloud_in->size() <<"\n--------------------"<< endl;
    double PointNumber = cloud_in->size();
    // 当还多于30%原始点云数据时
    while (cloud_in->points.size() > 0.1 * nr_points) {
        // 从余下的点云中分割最大平面组成部分
        seg.setInputCloud(cloud_in);
        seg.segment(*inliers, *coefficients);
        if (inliers->indices.size() == 0) {
            std::cerr << "Could not estimate a planar model for the given dataset." << std::endl;
            break;
        }

        // 分离内层
        extract.setInputCloud(cloud_in);
        extract.setIndices(inliers);
        extract.setNegative(false);
        extract.filter(*cloud_p);//将分割点云根据inliers提取到cloud_p中
        PointNumber = PointNumber - cloud_p->size();
        std::cerr << "after cloud_filtered: " << PointNumber << std::endl;//剩余的点云

        //保存
        std::cerr << "PointCloud representing the planar component: " << cloud_p->width * cloud_p->height
                  << " data points." << std::endl;
        std::stringstream ss;
        ss << "Plane_" << i <<"_"<< filename; //对每一次的提取都进行了文件保存
        writer.write<pcl::PointXYZ>(ss.str(), *cloud_p, false);
        cout<<ss.str()<<" saved!"<<endl;
        std::cerr << "----------------------------------" << std::endl;

        // 再次创建滤波器对象
        extract.setNegative(true);//提取外层
        extract.filter(*cloud_f);//将外层的提取结果保存到cloud_f
        cloud_in.swap(cloud_f);//经cloud_filtered与cloud_f交换


        i++;


    }
}

效果如图:

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tech沉思录

点赞加投币,感谢您的资瓷~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值