一个基于特征的统计突变而分割点云的处理过程及代码

最近需要处理优化点云,从一个点云数据中提出目标点云,如下图,我要提取出更大的那个椭圆点云。
在这里插入图片描述
分析:那个比较小的点云数据和比较大的点云数据,虽然在同一个平面上,但其在Y轴方向的位置上是有明显差异的,且我始终需要提取出最大的椭圆点云。
一开始使用了椭圆拟合,聚类分等方法,都看起来很复杂,而且吧只要涉及到距离容忍度都要调试设置。
理想思路:
分析数据发现,这个点云在Y坐标上完全分开的,如果我们能基于点云求得Y最大和最小点的坐标,然后作一条直线,然后计算直线与点云的交点(最近距离点),这样4个交点就把点云分成两段,我就可以基于分段的坐标点对点云过滤了。
在这里插入图片描述
确实,求得了如上4个点,再基于如下代码即可计算过滤出目标点云

pcl::PassThrough<pcl::PointXYZ> passFilter;
passFilter.setInputCloud(Inputcloud);
passFilter.setFilterFieldName("y");
passFilter.setFilterLimits(fStart, fEnd);//fStart, fEnd是如上交点的Y坐标
passFilter.filter(*Outputcloud);

但是,困难在于这些点云是散点,不太可能真的与直线有交点,其实需要求的还是距离最近的点,又会涉及到距离筛选和容忍度了。容忍度,做点云处理的人最最熟悉不过了。。。

那么还是来点不一样的思路吧,这也是今天记录这篇博客的原因~
因为经历了计算了椭圆拟合、面积比较,还有这个求直线、计算距离最近点这些过程,最后还是想用统计分段的方式去解决。
处理思路梳理:
(1)已知点云在Y轴上表现出了明显的类间差异,所以需要先将所有的点云投影到Y轴,其实就是提出Y坐标
(2)对Y坐标进行冒泡排序,没错,就是冒泡排序
(3)计算排序后的相邻坐标突变位置,其实就是计算排序后的相邻差值,找到差值最值
因为同类点云经过冒泡以后,相邻的突变其实很小的(类内的点云数据密度相对有保障),但类间的Y可是断崖是的突变。
(4)基于相邻差值最值反映射出适合分离两个类的Y值
只要找到差值突变值,然后求得其对应的两个位置,求得两个坐标的中值,那么基于Y坐标的分类阈值就get了。
在这里插入图片描述

我们的目标是求得更大的椭圆点云,而干扰点云与目标点云间有足够的距离,且目标点云和干扰点云都有自己规整的形状轮廓,这样类内部的相邻坐标就不存在那么大的突变,从而可以采用捕捉类间突变的思路。
(5)直接上代码段

可直接使用

        //-------------------过滤多余点-------------------------------
        std::vector<double> y_values;
        double fMin = mesh_filteredSecond->points[0].y, fMax = mesh_filteredSecond->points[0].y;
        //mesh_filteredSecond 为过滤前的点云
        for (const auto& point : mesh_filteredSecond->points) {
            if (fMin > point.y)
            {
                fMin = point.y;
            }
            if (fMax < point.y)
            {
                fMax = point.y;
            }
            y_values.push_back(point.y);
        }
        //冒泡排序
        bubble_sort(y_values, mesh_filteredSecond->points.size()); 

        //计算前半段差值
        std::vector<double> y_Delta1;
        int nStartY = 1;
        int nEndY = y_values.size()/2;
        for (int i = nStartY; i < nEndY; i++)
        {
            y_Delta1.push_back(y_values[i] - y_values[i - 1]);
        }
        double fMaxd1 = y_Delta1[0];
        int nInedx1 = 0;
        for (int i = 0; i < y_Delta1.size(); i++)
        {
            if (fMaxd1 < y_Delta1[i])
            {
                fMaxd1 = y_Delta1[i];
                nInedx1 = i;
            }
        }
        //计算后半段差值
        std::vector<double> y_Delta2;
        nStartY = y_values.size() / 2;
        nEndY = y_values.size();
        for (int i = nStartY; i < nEndY; i++)
        {
            y_Delta2.push_back(y_values[i] - y_values[i - 1]);
        }
        double fMaxd2 = y_Delta2[0];
        int nInedx2 = 0;
        for (int i = 0; i < y_Delta2.size(); i++)
        {
            if (fMaxd2 < y_Delta2[i])
            {
                fMaxd2 = y_Delta2[i];
                nInedx2 = i+ nStartY;
            }
        }
   
        if (fabs(fMaxd2 - fMaxd1) < 0.08) //突变阈值比较
        {
            if( (fMax - fMin) < 0.35)//椭圆过滤半径极限
            {
                pcl::copyPointCloud(*mesh_filteredSecond, *mesh_Finalfiltered);
            }
            else//三分类情况
            {
                int nlen1 = nInedx2 -nInedx1;
                int nlen2 = y_values.size() - nInedx2;                    
                double fY1 = (y_values[nInedx1] + y_values[nInedx1 + 1]) / 2;
                double fY2 = (y_values[nInedx2-1] + y_values[nInedx2 ]) / 2; 
                if ((nlen1 > nInedx1 && nlen1 > nlen2) || fabs(fY1+ fY2)<0.05)
                {
                    doPassThrough("y", fY1 , fY2, mesh_filteredSecond, mesh_Finalfiltered);
                }
                else if (nlen1 > nInedx1) 
                {
                    doPassThrough("y", fY2,fMax+0.001, mesh_filteredSecond, mesh_Finalfiltered);
                }
                else if (nlen1 > nlen2)
                {
                    doPassThrough("y", fMin - 0.001, fY1, mesh_filteredSecond, mesh_Finalfiltered);
                }
                else 
                {
                    if (nInedx1 > nlen2)
                    {
                        doPassThrough("y", fMin - 0.001, fY1, mesh_filteredSecond, mesh_Finalfiltered);
                    }
                    else
                    {
                        doPassThrough("y", fY2, fMax + 0.001, mesh_filteredSecond, mesh_Finalfiltered);
                    }
                }
            }
        }
        else 
        {
            if (fMaxd1 > fMaxd2) 
            {
                double fY = (y_values[nInedx1] + y_values[nInedx1 + 1]) / 2;
                doPassThrough("y", fY, fMax + 0.001, mesh_filteredSecond, mesh_Finalfiltered);
            }
            else 
            {
                double fY = (y_values[nInedx2-1] + y_values[nInedx2]) / 2;
                doPassThrough("y", fMin - 0.001, fY, mesh_filteredSecond, mesh_Finalfiltered);
            }
        }

冒泡排序

void bubble_sort(std::vector<double> &y_values, int len)
{
    int i, j;
    double temp = 0.f;
    for (i = 0; i < len - 1; i++)
        for (j = 0; j < len - 1 - i; j++)
            if (y_values[j] > y_values[j + 1])
            {
                temp = y_values[j];
                y_values[j] = y_values[j + 1];
                y_values[j + 1] = temp;
            }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值