点云聚类与区域边界估计

Posted lovebay

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了点云聚类与区域边界估计相关的知识,希望对你有一定的参考价值。

点云聚类与区域边界估计

  为对有一定特征和规律的点云数据进行聚类划分,文章提出了一种将空间与特性融合的聚类方法,并在聚类的基础上进行了区域边界的检测(这是上一边文章提到的方法),具体算法思路如下:

(1)点云预处理抽希、去燥等

(2)不可划分区域剔除;

(3)下面就是把剩余区域进行聚类划分,选取x最大的面作为搜索种子面开始,进行邻近半径搜索,设半径为R,当在半径R内搜索到n个三角面后,比较这些三角面与加权平均mid_d的差值,设置阈值delta_d, 若间距差值小于阈值delta_d,则将所搜到的三角面进行一个聚类custer的融合,否则,则不融合;然后新进来的面有作为种子面,进行上面继续搜索,并计算新的加权平均间距mid_d。这样迭代下去,直到所有的所有聚类划分完成。

 技术图片

示意图

(4)通过第三步可以得到很多聚类结果custers,遍历所有聚类custers,设置最小点数或面积阈值A3,剔除面积小于A3的聚类custer;对每个custer进行三角面融合以及边界检测。

(5)对第四步的检测边界,进行锯齿处理,主要采用边界平滑处理,有个平滑力度阈值dis_threshold作为区域边界;返回这些区域边界数据。

(注:主要第三步是把两步划分,进行一步划分聚类)

 

部分代码:

int Division(
    std::vector<PointType>& in_points,
    std::vector<PCTTM_TriangleFace>& face_vect,
    std::vector<double>& distance_vect,
    std::vector<PointType>& face_center_points2,
    std::vector<std::vector<int>>& region_vector, 
    const double& d_threshold, 
    const int& num_threshold) {

    if (in_points.size()<3 || face_vect.size()==0|| distance_vect.size()==0)
    {
        std::cout << "in_points.size()<3 || face_vect.size()==0|| distance_vect.size()==0" << std::endl;
        return -1;
    }

    std::vector<PointType> face_center_points;
    //std::vector<point3f_rgba> face_center_points2;
    //计算三角面几何中心 
    std::vector<double> distance_vect2;     //剔除灰色
    std::vector<int> out_index(face_vect.size());
    for (size_t i = 0; i < face_vect.size(); i++)
    {
        PointType pt2 = calculateFaceCenter(in_points[face_vect[i].p_index_0], in_points[face_vect[i].p_index_1], in_points[face_vect[i].p_index_2]);

        int d_index = static_cast<int>(10.0*d_threshold / 5.0);
        int index = static_cast<int>(10.0*distance_vect[i] / 5.0);
        if (distance_vect[i] <= d_threshold)
        {
            face_center_points2.push_back(pt2);
            distance_vect2.push_back(distance_vect[i]);
        }
        else
        {
            out_index[i] = -1;
        }
        face_center_points.push_back(pt2);
    }

    /*****************离散点的区域划分*************************/
    KDT::KDTree tree;
    tree.setInputPointCloud(face_center_points2);
    tree.setNumOfLeafData(100);
    tree.buildKDTree();

    double density = 0.0;
    if (caculateDensity(face_center_points2, density) == -1) {
        std::cout << "caculateDensity() failed !!! " << std::endl;
        return -1;
    }

    const double delta_threshold = 1.49999;  //0.3-3.0
    const float searchRadius = 3.0*density;   //点云平均密度的1-3倍

    //std::vector<std::vector<int>> region_vector;
    std::vector<int> index_(face_center_points2.size());
    for (size_t i = 0; i < face_center_points2.size(); i++)
    {
        if (index_[i] == -1)
        {
            continue;
        }

        std::vector<int> region_;
        double mid_d = 0.0;

        /*****************迭代循环搜索************************/
        region_.push_back(i);
        index_[i] = -1;
        int t = 0;
        mid_d = distance_vect2[i];
        while (t < region_.size())
        {
            //mid_d = distance_vect2[region_[t]];
            const PointType searchPoint2 = face_center_points2[region_[t]];
            std::vector<size_t> searchIndex2;
            std::vector<float> searchDistance2;
            double dis = 0.0;
            int num = 0;
            if (tree.runKNNSearchRadius(searchPoint2, searchRadius, searchIndex2, searchDistance2) > 1) {
                for (size_t n = 0; n < searchIndex2.size(); n++)
                {
                    if (index_[searchIndex2[n]] != -1 && abs(distance_vect2[searchIndex2[n]] - mid_d) < delta_threshold)
                    {
                        region_.push_back(searchIndex2[n]);
                        index_[searchIndex2[n]] = -1;
                        dis += distance_vect2[searchIndex2[n]];
                        num++;
                    }
                }
            }

            mid_d = (dis + mid_d*(region_.size() - num)) / region_.size();
            t++;
        }
        //存取大于   的分域
        if (region_.size() > num_threshold)
        {
            region_vector.push_back(region_);
        }
    }

    return 0;
}

 

效果:

 

技术图片

 

以上是关于点云聚类与区域边界估计的主要内容,如果未能解决你的问题,请参考以下文章

Freeman链码

根据种子点识别多边形边界的最佳方法是啥?

区域填充算法

图像形态学提取边界和区域填充

【Autoware】配置镭神激光雷达lslidar-c16并完成点云聚类检测

ArcGIS中,可不可以把某一区域的边界由实线转换为虚线?