pclpy Ransac平面分割算法输出的索引从点云中提取点云的子集

pclpy Ransac平面分割算法输出的索引从点云中提取点云的子集

一、算法原理

1、Ransac介绍

RANSAC(RAndom SAmple Consensus,随机采样一致)算法是从一组含有"外点"(outliers)的数据中正确估计数学模型参数的迭代算法。"外点"一般指的是数据中的噪声,比如说匹配中的误匹配和估计曲线中的离群点。所以,RANSAC也是一种"外点"检测算法。RANSAC算法是一种不确定算法,它只能在一种概率下产生结果,并且这个概率会随着迭代次数的增加而加大(之后会解释为什么这个算法是这样的)。

RANSAC主要解决样本中的外点问题,最多可处理50%的外点情况。


范例

可以简单总结为以下步骤:

N:样本个数 K:求解模型需要的最少的点的个数(对于直线拟合来说就是两个点,对于计算Homography矩阵就是四个点)

随机采样K个点

对该K个点拟合模型

计算其他点到拟合模型的距离。如果小于一定阈值,该点被当作内点,统计内点个数

重复M次,选择内点数最多的模型

利用所有的内点重新估计模型(可选)

RANSAC用于拟合直线:

1.随机选取K = 2 ,2个点:

2.拟合一条直线:

3.统计内点个数,内点为绿色,此时的内点个数为9(小于一定阈值计算为内点):

4.重复上述过程M次,找到内点数最大的模型(继续随机选点根据k=数目进行选点):

5.利用所有的内点重新估计直线:

二、代码

python 复制代码
from pclpy import pcl

def compareCloudShow(cloud1, cloud2):
    """
    Args:在一个窗口生成2个窗口可视化点云
        cloud1: 点云数据1
        cloud2: 点云数据2
    """
    viewer = pcl.visualization.PCLVisualizer("viewer")  # 建立可刷窗口对象 窗口名 viewer
    v0 = 1  # 设置标签名(0, 1标记第一个窗口)
    viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v0)  # 创建一个可视化的窗口
    viewer.setBackgroundColor(0.0, 0.0, 0.0, v0)  # 设置窗口背景为黑色
    single_color = pcl.visualization.PointCloudColorHandlerCustom.PointXYZ(cloud1, 255.0, 0, 0.0)  # 将点云设置为红色
    viewer.addPointCloud(cloud1,          # 要添加到窗口的点云数据。
                         single_color,    # 指定点云的颜色
                         "sample cloud1",  # 添加的点云命名
                         v0)  # 点云添加到的视图

    v1 = 2  # 设置标签名(2代表第二个窗口)
    viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v1)  # 创建一个可视化的窗口
    viewer.setBackgroundColor(255.0, 255.0, 255.0, v1)  # 设置窗口背景为白色
    single_color = pcl.visualization.PointCloudColorHandlerCustom.PointXYZ(cloud2, 0.0, 255.0, 0.0)  # 将点云设置为绿色
    viewer.addPointCloud(cloud2,  # 要添加到窗口的点云数据。
                         single_color,  # 指定点云的颜色
                         "sample cloud2",  # 添加的点云命名
                         v1)  # 点云添加到的视图

    # 设置点云窗口(可移除对点云可视化没有影响)
    viewer.setPointCloudRenderingProperties(0,  # 设置点云点的大小
                                            1,  # 点云像素
                                            "sample cloud1",  # 识别特定点云
                                            v0)  # 在那个窗口可视化
    viewer.setPointCloudRenderingProperties(0,  # 设置点云点的大小
                                            1,  # 点云像素
                                            "sample cloud2",  # 识别特定点云
                                            v1)  # 在那个窗口可视化
    viewer.addCoordinateSystem(1.0)  # 设置坐标轴 坐标轴的长度为1.0
    # 窗口建立
    while not viewer.wasStopped():
        viewer.spinOnce(10)


if __name__ == '__main__':
    # 读取点云数据
    cloud = pcl.PointCloud.PointXYZ()
    reader = pcl.io.PCDReader()
    reader.read('res/table_scene_lms400.pcd', cloud)
    print('点云数目:', cloud.size())

    # 创建sor滤波器 参考 pclpy SOR去除异常值(统计滤波) pclpy专栏中
    cloud_filtered = pcl.PointCloud.PointXYZ()
    sor = pcl.filters.StatisticalOutlierRemoval.PointXYZ()  # 创建sor处理对象
    sor.setInputCloud(cloud)  # 将cloud处理
    sor.setMeanK(50)  # 每个点要分析的邻居数
    sor.setStddevMulThresh(1.0)  # 距离查询点的平均距离大于1个标准差的点都将被标记为离群值并删除
    sor.filter(cloud_filtered)  # sor处理后的点云保存在这里(内点)

    # 可视化滤波效果
    compareCloudShow(cloud, cloud_filtered)  # 参考 pclpy 可视化点云(多窗口可视化、单窗口多点云可视化) pclpy在专栏中

    coeffs = pcl.ModelCoefficients()  # 存储估计的平面参数
    inliers = pcl.PointIndices()  # 存储平面模型的内点索引
    # 创建分割object
    seg = pcl.segmentation.SACSegmentation.PointXYZ()
    # 可选项
    seg.setOptimizeCoefficients(True)
    # 设置
    seg.setModelType(0)  # 0平面模型
    seg.setMethodType(0)  # 表示 RANSAC 算法  open3d 平面分割(Ransac算法) 专栏open3d
    seg.setMaxIterations(1000)  # 设置 RANSAC 算法的最大迭代次数为 1000。
    seg.setDistanceThreshold(0.01)  # 设置平面模型的距离阈值为 0.01,用于判断点是否为内点(inliers)

    # 创建滤波object
    extract = pcl.filters.ExtractIndices.PointXYZ()
    nr_points = cloud_filtered.size()  # 获得点云数目
    while cloud_filtered.size() > nr_points * 0.3:
        # 从保留的点云中分割最大的平面成分
        seg.setInputCloud(cloud_filtered)  # 将滤波后的点云数据设置为分割器的输入
        seg.segment(inliers, coeffs)  # 分割后的内点索引保存在 inliers 中,将平面模型系数保存在 coeffs
        if len(inliers.indices) == 0:
            print('无法对给定数据集估计平面模型。')
            break

        # 提取内点(平面成分)
        extract.setInputCloud(cloud_filtered)  # 从点云中提取指定索引的点 和 open3d 中的select_index_by()一样
        extract.setIndices(inliers)  # 将计算索引进行装填
        extract.setNegative(False)  # 获得内点
        cloud_p = pcl.PointCloud.PointXYZ()
        extract.filter(cloud_p)
        # 可视化提取出来的平面
        compareCloudShow(cloud_filtered, cloud_p)
        print("点云数目:", cloud_p.size())

        # 再次滤波,提取外点(非平面成分)
        extract.setNegative(True)   # 获得外点
        cloud_f = pcl.PointCloud.PointXYZ()  
        extract.filter(cloud_f)
        cloud_filtered.swap(cloud_f)  # 等价于cloud_filtered = cloud_f

三、结果

1.sor统计滤波
2.Ransac内点分割平面
3.Ransac外点分割平面

四、相关数据

pclpy SOR去除异常值(统计滤波):pclpy SOR去除异常值(统计滤波)-CSDN博客

pclpy 可视化点云(多窗口可视化、单窗口多点云可视化):pclpy 可视化点云(多窗口可视化、单窗口多点云可视化)-CSDN博客

open3d 平面分割(Ransac算法) open3d 平面分割(Ransac算法)-CSDN博客

相关推荐
一点媛艺2 小时前
Kotlin函数由易到难
开发语言·python·kotlin
程序小旭2 小时前
机器视觉基础—双目相机
计算机视觉·双目相机
魔道不误砍柴功3 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
pianmian13 小时前
python数据结构基础(7)
数据结构·算法
_.Switch3 小时前
高级Python自动化运维:容器安全与网络策略的深度解析
运维·网络·python·安全·自动化·devops
AI极客菌4 小时前
Controlnet作者新作IC-light V2:基于FLUX训练,支持处理风格化图像,细节远高于SD1.5。
人工智能·计算机视觉·ai作画·stable diffusion·aigc·flux·人工智能作画
阿_旭4 小时前
一文读懂| 自注意力与交叉注意力机制在计算机视觉中作用与基本原理
人工智能·深度学习·计算机视觉·cross-attention·self-attention
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
测开小菜鸟4 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
好奇龙猫5 小时前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法