激光雷达点云地平面校准 地面分割

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014679795/article/details/82189901

步骤:

1. 加载点云,显示,白色点云

2. 鼠标选取地面部分点云,作为校准标准

void pp_callback(const pcl::visualization::AreaPickingEvent& event, void* args)
{
    std::vector< int > indices;
    if (event.getPointsIndices(indices)==-1)
        return;

    for (int i = 0; i < indices.size(); ++i)
    {
        clicked_points_3d->points.push_back(cloud->points.at(indices[i]));
    }

    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> red(clicked_points_3d, 255, 0, 0);

    std::stringstream ss;
    std::string cloudName;
    ss << num++;
    ss >> cloudName;
    cloudName += "_cloudName";

    viewer->addPointCloud(clicked_points_3d, red, cloudName);
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, cloudName);
}

3.将选取的点云拟合平面,计算法向量

bool estimateGroundPlane(pcl::PointCloud<pcl::PointXYZRGB>::Ptr &in_cloud, pcl::PointCloud<pcl::PointXYZRGB>::Ptr &out_cloud,
                         const float in_distance_thre)
{
    //plane segmentation
    pcl::SACSegmentation<pcl::PointXYZRGB> plane_seg;
    pcl::PointIndices::Ptr plane_inliers ( new pcl::PointIndices );
    pcl::ModelCoefficients::Ptr plane_coefficients ( new pcl::ModelCoefficients );
    plane_seg.setOptimizeCoefficients (true);
    plane_seg.setModelType ( pcl::SACMODEL_PLANE );
    plane_seg.setMethodType ( pcl::SAC_RANSAC );
    plane_seg.setDistanceThreshold ( in_distance_thre );
    plane_seg.setInputCloud ( in_cloud );
    plane_seg.segment ( *plane_inliers, *plane_coefficients );

    pcl::ExtractIndices<pcl::PointXYZRGB> extract;
    extract.setInputCloud (in_cloud);
    extract.setIndices (plane_inliers);
    extract.filter (*out_cloud);
    cout<<"cloud size="<<out_cloud->size()<<endl;
    return true;
}

计算平面法向量

    pcl::PointCloud<pcl::PointXYZRGB>::Ptr out_cloud(new pcl::PointCloud<pcl::PointXYZRGB>); // 创建点云(指针)
    estimateGroundPlane(clicked_points_3d,out_cloud,0.1);
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
    //创建法线估计的对象
    pcl::NormalEstimation<pcl::PointXYZRGB,pcl::Normal> normalEstimation;
    normalEstimation.setInputCloud(out_cloud);
    //对于每一个点都用半径为10m的近邻搜索方式
    normalEstimation.setRadiusSearch(10);
    //Kd_tree是一种数据结构便于管理点云以及搜索点云,法线估计对象会使用这种结构来找到哦啊最近邻点
    pcl::search::KdTree<pcl::PointXYZRGB>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZRGB>);
    normalEstimation.setSearchMethod(kdtree);
    //计算法线
    normalEstimation.compute(*normals);

4.根据法向量,计算旋转矩阵


Eigen::Matrix4f CreateRotateMatrix(Eigen::Vector3f before,Eigen::Vector3f after)
{
    before.normalize();
    after.normalize();

    float angle = acos(before.dot(after));
    Eigen::Vector3f p_rotate =before.cross(after);
    p_rotate.normalize();

    Eigen::Matrix4f rotationMatrix = Eigen::Matrix4f::Identity();
    rotationMatrix(0, 0) = cos(angle) + p_rotate[0] * p_rotate[0] * (1 - cos(angle));
    rotationMatrix(0, 1) = p_rotate[0] * p_rotate[1] * (1 - cos(angle) - p_rotate[2] * sin(angle));//这里跟公式比多了一个括号,但是看实验结果它是对的。
    rotationMatrix(0, 2) = p_rotate[1] * sin(angle) + p_rotate[0] * p_rotate[2] * (1 - cos(angle));


    rotationMatrix(1, 0) = p_rotate[2] * sin(angle) + p_rotate[0] * p_rotate[1] * (1 - cos(angle));
    rotationMatrix(1, 1) = cos(angle) + p_rotate[1] * p_rotate[1] * (1 - cos(angle));
    rotationMatrix(1, 2) = -p_rotate[0] * sin(angle) + p_rotate[1] * p_rotate[2] * (1 - cos(angle));


    rotationMatrix(2, 0) = -p_rotate[1] * sin(angle) +p_rotate[0] * p_rotate[2] * (1 - cos(angle));
    rotationMatrix(2, 1) = p_rotate[0] * sin(angle) + p_rotate[1] * p_rotate[2] * (1 - cos(angle));
    rotationMatrix(2, 2) = cos(angle) + p_rotate[2] * p_rotate[2] * (1 - cos(angle));

    return rotationMatrix;
}

5.旋转点云,并显示,绿色点云

效果:

效果点云1
标题

全部代码见链接

猜你喜欢

转载自blog.csdn.net/u014679795/article/details/82189901