使用open3d分离背景和物体点云

news2024/11/24 13:37:52

一、代码

方法简单介绍

RANSAC(随机采样一致性)是一种常用的分割算法,通常用于从点云中分割出最大的平面(如地面、墙壁等)。RANSAC速度相对较快,特别是当点云数据量不是很大时。在物体与背景之间存在明显的平面界限时效果较好,但如果背景复杂或物体表面也较平坦,则可能无法有效分割。

DBSCAN(基于密度的空间聚类的噪声应用)是一个无监督的聚类算法,能够根据密度将数据分割成多个子集群。DBSCAN的运行时间主要取决于点云的密度和大小。对于大型点云,DBSCAN可能会比较慢。对于分离具有不同密度分布的物体和背景,DBSCAN通常效果不错。参数选择对结果有很大影响。

Python

import open3d as o3d
import matplotlib.pyplot as plt
import numpy as np


def ransacDbscanPlaneSeg(pointcloud):
    plane_model, inliers = pointcloud.segment_plane(distance_threshold=0.001,
                                                    ransac_n=3,
                                                    num_iterations=1000)
    # 提取平面点云和非平面点云
    plane_pcd = pointcloud.select_by_index(inliers)
    objects_pcd = pointcloud.select_by_index(inliers, invert=True)

    # 对非平面部分进行欧几里得聚类分割
    with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
        labels = np.array(objects_pcd.cluster_dbscan(eps=0.05, min_points=10, print_progress=True))

    # 根据标签为每个聚类赋予不同颜色
    max_label = labels.max()
    label, counts = np.unique(labels, return_counts=True)
    # 忽略噪声点,其标签为-1
    counts = counts[label != -1]
    label = label[label != -1]
    # 找到点数最多的聚类的标签
    max_points_cluster_label = label[counts.argmax()]
    colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
    colors[labels < 0] = 0  # 为噪声点赋予黑色
    objects_pcd.colors = o3d.utility.Vector3dVector(colors[:, :3])

    most_points_cluster_indices = np.where(labels == max_points_cluster_label)[0]
    most_points_cluster_pcd = objects_pcd.select_by_index(most_points_cluster_indices)
    return plane_pcd, most_points_cluster_pcd


def dbscanPlaneSeg(pointcloud):
    # 进行DBSCAN聚类分割
    # eps参数定义了领域的半径,min_points定义了形成一个聚类所需的最小点数
    labels = np.array(pointcloud.cluster_dbscan(eps=0.001, min_points=20, print_progress=True))
    # 获取最大的标签值(最大的聚类索引)
    max_label = labels.max()
    # print("point cloud has %s clusters" % (max_label + 1))
    # 为了找到点数最多的聚类,我们将统计每个聚类标签出现的次数
    label, counts = np.unique(labels, return_counts=True)
    # 忽略噪声点,其标签为-1
    counts = counts[label != -1]
    label = label[label != -1]
    # 找到点数最多的聚类的标签
    max_points_cluster_label = label[counts.argmax()]
    # 将聚类结果转换成不同颜色
    colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
    colors[labels < 0] = 0  # 将未分类的点(噪声)设置成黑色
    pointcloud.colors = o3d.utility.Vector3dVector(colors[:, :3])

    # 可视化聚类分割的点云
    # o3d.visualization.draw_geometries([pointcloud])

    # 可选:根据标签提取特定聚类
    # cluster_indices = np.where(labels == 0)[0]  # 提取标签为0的聚类
    # cluster_pcd = pcd.select_by_index(cluster_indices)
    # o3d.visualization.draw_geometries([cluster_pcd])
    # 提取点数最多的聚类
    most_points_cluster_indices = np.where(labels == max_points_cluster_label)[0]
    most_points_cluster_pcd = pointcloud.select_by_index(most_points_cluster_indices)
    return pointcloud, most_points_cluster_pcd


def ransacPlaneSeg(pointcloud):
    # RANSAC平面分割
    plane_model, inliers = pointcloud.segment_plane(distance_threshold=0.001,
                                                    ransac_n=4,
                                                    num_iterations=1000)
    # 提取平面内的点云
    inlier_cloud = pointcloud.select_by_index(inliers)
    # 提取平面外的点云
    outlier_cloud = pointcloud.select_by_index(inliers, invert=True)
    return inlier_cloud, outlier_cloud


if __name__ == "__main__":
    # 加载点云
    pcd = o3d.io.read_point_cloud("res/1.ply")
    o3d.visualization.draw_geometries([pcd])
    # _, result = ransacPlaneSeg(pcd)
    _, result = dbscanPlaneSeg(pcd)

    o3d.visualization.draw_geometries([result])

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

关键代码解析:

 

def ransacDbscanPlaneSeg(pointcloud):
    plane_model, inliers = pointcloud.segment_plane(distance_threshold=0.001,
                                                    ransac_n=3,
                                                    num_iterations=1000)
    # 提取平面点云和非平面点云
    plane_pcd = pointcloud.select_by_index(inliers)
    objects_pcd = pointcloud.select_by_index(inliers, invert=True)

    # 对非平面部分进行欧几里得聚类分割
    with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
        labels = np.array(objects_pcd.cluster_dbscan(eps=0.05, min_points=10, print_progress=True))

    # 根据标签为每个聚类赋予不同颜色
    max_label = labels.max()
    label, counts = np.unique(labels, return_counts=True)
    # 忽略噪声点,其标签为-1
    counts = counts[label != -1]
    label = label[label != -1]
    # 找到点数最多的聚类的标签
    max_points_cluster_label = label[counts.argmax()]
    colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
    colors[labels < 0] = 0  # 为噪声点赋予黑色
    objects_pcd.colors = o3d.utility.Vector3dVector(colors[:, :3])

    most_points_cluster_indices = np.where(labels == max_points_cluster_label)[0]
    most_points_cluster_pcd = objects_pcd.select_by_index(most_points_cluster_indices)
    return plane_pcd, most_points_cluster_pcd


def dbscanPlaneSeg(pointcloud):
    # 进行DBSCAN聚类分割
    # eps参数定义了领域的半径,min_points定义了形成一个聚类所需的最小点数
    labels = np.array(pointcloud.cluster_dbscan(eps=0.001, min_points=20, print_progress=True))
    # 获取最大的标签值(最大的聚类索引)
    max_label = labels.max()
    # print("point cloud has %s clusters" % (max_label + 1))
    # 为了找到点数最多的聚类,我们将统计每个聚类标签出现的次数
    label, counts = np.unique(labels, return_counts=True)
    # 忽略噪声点,其标签为-1
    counts = counts[label != -1]
    label = label[label != -1]
    # 找到点数最多的聚类的标签
    max_points_cluster_label = label[counts.argmax()]
    # 将聚类结果转换成不同颜色
    colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
    colors[labels < 0] = 0  # 将未分类的点(噪声)设置成黑色
    pointcloud.colors = o3d.utility.Vector3dVector(colors[:, :3])

    # 可视化聚类分割的点云
    # o3d.visualization.draw_geometries([pointcloud])

    # 可选:根据标签提取特定聚类
    # cluster_indices = np.where(labels == 0)[0]  # 提取标签为0的聚类
    # cluster_pcd = pcd.select_by_index(cluster_indices)
    # o3d.visualization.draw_geometries([cluster_pcd])
    # 提取点数最多的聚类
    most_points_cluster_indices = np.where(labels == max_points_cluster_label)[0]
    most_points_cluster_pcd = pointcloud.select_by_index(most_points_cluster_indices)
    return pointcloud, most_points_cluster_pcd


def ransacPlaneSeg(pointcloud):
    # RANSAC平面分割
    plane_model, inliers = pointcloud.segment_plane(distance_threshold=0.001,
                                                    ransac_n=4,
                                                    num_iterations=1000)
    # 提取平面内的点云
    inlier_cloud = pointcloud.select_by_index(inliers)
    # 提取平面外的点云
    outlier_cloud = pointcloud.select_by_index(inliers, invert=True)
    return inlier_cloud, outlier_cloud
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

这段代码包含了三个函数,它们分别使用基于欧几里得距离的DBSCAN算法与RANSAC平面分割算法来处理三维点云数据。

  1. ransacDbscanPlaneSeg(pointcloud):

    • 这个函数首先利用RANSAC算法分割出点云中的一个平面。

    • 然后将点云分成属于平面的点与不属于平面的点。

    • 对不属于平面的点云进行DBSCAN聚类。

    • 找到包含点数最多的那个聚类,并将其返回。

  2. dbscanPlaneSeg(pointcloud):

    • 仅使用DBSCAN算法对整个点云进行聚类。

    • 找到并返回包含点数最多的那个聚类。

  3. ransacPlaneSeg(pointcloud):

    • 仅使用RANSAC算法分割出点云中的平面,并返回属于平面的点和不属于平面的点。

每个函数中都有一些参数可以调整,这些参数会对算法的结果产生影响:

  • distance_threshold: RANSAC算法中,一个点被认为是平面上的点的最大距离。这个值越小,认定为平面上点的条件越严格。

  • ransac_n: RANSAC算法中,用于估计平面模型的点的最小数量。这个数值通常设置为3,因为理论上3个非共线的点可以确定一个平面。

  • num_iterations: RANSAC算法的迭代次数,迭代次数越多,找到最佳模型的概率越大,但计算时间也会增加。

  • eps: DBSCAN算法中领域的半径,也就是用来确定其他点是否与某一点处在同一邻域的距离阈值。这个值越小,形成簇的条件越严格,可能会得到更多的、更小的簇。

  • min_points: DBSCAN算法中,定义了一个点要成为核心点所需的邻域内邻近点的最小数量。这个数值越大,算法识别出的核心点越少,簇的数量也越少。

在实际应用中,需要根据点云的密度以及您想要识别的对象的大小和分布特征来调整这些参数。例如,点云数据中的物体距离彼此非常近,您可能需要减小eps以避免将多个物体错误地合并到同一个簇中。

最后,这些函数通常会返回两个点云:一个包含平面点的点云,另一个是聚类后点数最多的那个物体的点云。如果您需要可视化这些点云以检查分割和聚类的效果,可以使用o3d.visualization.draw_geometries函数进行可视化。

结果:

处理前

处理后

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1559526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯 本质上升序列

题目描述: 小蓝特别喜欢单调递增的事物。 在一个字符串中&#xff0c;如果取出若干个字符&#xff0c;将这些字符按照在字符串中的顺序排列后是单调递增的&#xff0c;则成为这个字符串中的一个单调递增子序列。 例如&#xff0c;在字符串 lanqiao 中&#xff0c;如果取出字符…

蓝桥杯省赛刷题——题目 2656:刷题统计

刷题统计OJ链接&#xff1a;蓝桥杯2022年第十三届省赛真题-刷题统计 - C语言网 (dotcpp.com) 题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a 道题目&#xff0c;周六和周日每天做 b 道题目。请你帮小明计算&#xff0c;按照计划他将在第几…

Segger Embedded Studio IDE使用体验——默认的Section和Linker的设置

Segger Embedded Studio IDE使用体验之一——默认的Section和Linker的设置 一、简介二、操作2.1 编译后代码分析2.1.1 符号浏览器2.1.2 读取elf文件和map文件 2.2 调试2.2.1 查看变量2.2.2 设置供电 2.3 运行环境设置2.3.1 编译器2.3.2 汇编器2.3.3 包含其他文件2.3.4 .bss和.d…

iOS问题记录 - App Store审核新政策:隐私清单 SDK签名(持续更新)

文章目录 前言开发环境问题描述问题分析1. 隐私清单 & SDK签名1.1. 隐私清单 - 数据使用声明1.2. 隐私清单 - 所用API原因描述1.3. SDK签名 2. 即将发布的第三方SDK要求 解决方案最后 前言 前段时间用Flutter开发的iOS App提交了新版本&#xff0c;结果刚过两分钟就收到了…

基于springboot实现旅游网站系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现旅游网站系统演示 摘要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;旅游网站当然也不能排除在外&#xff0c;随着旅游网站的不断成熟&#xff0c;它彻底改变了过去传统的旅游…

魔改一个过游戏保护的CE

csdn审核不通过 网易云课堂有配套的免费视频 int0x3 - 主页 文章都传到github了 Notes/外挂/魔改CE at master MrXiao7/Notes GitHub 为什么要编译自己的CE 在游戏逆向的过程中&#xff0c;很多游戏有保护&#xff0c;我们运行原版CE的时候会被检测到 比如我们开着CE运…

【AXIS】AXI-Stream FIFO设计实现(四)——异步时钟

前文介绍了几种同步时钟情况下的AXI Stream FIFO实现方式&#xff0c;一般来说&#xff0c;FIFO也需要承担异步时钟域模块间数据传输的功能&#xff0c;本文介绍异步AXIS FIFO的实现方式。 如前文所说&#xff0c;AXI-Stream FIFO十分类似于FWFT异步FIFO&#xff0c;推荐参考前…

AtCoder Beginner Contest 347 (ABCDEF题)视频讲解

A - Divisible Problem Statement You are given positive integers N N N and K K K, and a sequence of length N N N, A ( A 1 , A 2 , … , A N ) A(A_1,A_2,\ldots,A_N) A(A1​,A2​,…,AN​). Extract all elements of A A A that are multiples of K K K, divi…

2-HDFS常用命令及上传下载流程

HDFS NameNode 安全模式(safemode) 当NameNode被重启的时候&#xff0c;自动进入安全模式 在安全模式中&#xff0c;NameNode首先会触发edits_inprogress文件的滚动。滚动完成之后&#xff0c;更新fsimage文件 更新完成之后&#xff0c;NameNode会将fsimage文件中的元数据加…

新闻管理系统(源码+文档)

新闻管理系统&#xff08;小程序、ios、安卓都可部署&#xff09; 文件包含内容程序简要说明含有功能项目截图客户端新闻详情新闻首页分类退出登录个人中心拨打客服热线注册界面个人资料新闻评论成功 管理端用户管理分类管理新闻管理 文件包含内容 1、搭建视频 2、流程图 3、开…

特征融合篇 | 利用RT-DETR的AIFI去替换YOLOv8中的SPPF(附2种改进方法)

前言:Hello大家好,我是小哥谈。RT-DETR模型是一种用于目标检测的深度学习模型,它基于transformer架构,特别适用于实时处理序列数据。在RT-DETR模型中,AIFI(基于注意力的内部尺度特征交互)模块是一个关键组件,它通过引入注意力机制来增强模型对局部和全局信息的处理能力…

网络编程的学习1

网络编程 在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;进行数据传输。 三要素 ip&#xff1a;设备在网络中的地址&#xff0c;是唯一的标识。 ipv4:采取32位地址长度&#xff0c;分成4组。 ipv6&#xff1a;采用128位地址长度&#xff0c;分成8组。 …

阿里云优惠券领取方法大公开,省钱不再是难事

阿里云作为国内领先的云计算服务提供商&#xff0c;为广大用户提供了丰富的云产品和解决方案。为了吸引用户上云&#xff0c;阿里云经常推出各种优惠活动&#xff0c;其中最受用户欢迎的就是阿里云优惠券。那么&#xff0c;阿里云优惠券究竟是什么呢&#xff1f;我们又该如何领…

pygame通过重心坐标 用纹理填充三角形

texture_x int(alpha * texture_image.get_width()) texture_y int(beta * texture_image.get_height())为什么没有gama 2024/3/30 15:45:52 在使用重心坐标进行纹理映射时&#xff0c;通常是通过计算 alpha 和 beta 来确定纹理图片上的对应位置&#xff0c;而 gamma 通常是…

【QT学习】2.补充:connect中的lambda表达式

一.简单实例&#xff1a; 1.实例要求 点击按钮&#xff0c;实现 >o<与#-#的转换。 2.步骤 补充&#xff1a;​​​​​​​ 1.如果我想在lambda中修改数据&#xff0c;怎么办&#xff1f; 写上mutable就行。

共享办公室是否可以用来搭建直播间

共享办公室确实可以用来搭建直播间&#xff0c;这在很多创业公司和个人创作者中已经变得相当普遍。以下是一些实际可行的因素&#xff1a; 空间的私密性&#xff1a;选择一个较为封闭的空间&#xff0c;可以减少外界干扰&#xff0c;保证直播过程中的安静和专注。 良好的网络连…

鸿蒙TypeScript入门学习第4天:【TS变量声明】

1、TypeScript 变量声明 变量是一种使用方便的占位符&#xff0c;用于引用计算机内存地址。 我们可以把变量看做存储数据的容器。 TypeScript 变量的命名规则&#xff1a; 变量名称可以包含数字和字母。除了下划线 _ 和美元 $ 符号外&#xff0c;不能包含其他特殊字符&…

前端三剑客 —— CSS (第二节)

目录 内容回顾&#xff1a; CSS选择器*** 属性选择器 伪类选择器 1&#xff09;:link 超链接点击之前 2&#xff09;:visited 超链接点击之后 3&#xff09;:hover 鼠标悬停在某个标签上时 4&#xff09;:active 鼠标点击某个标签时&#xff0c;但没有松开 5&#xff09;:fo…

什么是服务雪崩?什么是服务限流?

服务雪崩效应&#xff1a;因服务提供者的不可用而导致服务调用者的不可用&#xff0c;并且这种情况不断的衍生方法&#xff0c;从而导致整个系统崩溃的过程&#xff0c;就是服务雪崩效应。 解决方式&#xff1a; 熔断机制&#xff1a;当一个服务挂了&#xff0c;被影响的服务要…

基于微信小程序的自习室预约系统的设计与实现

基于微信小程序的自习室预约系统的设计与实现 文章目录 基于微信小程序的自习室预约系统的设计与实现1、前言介绍2、功能设计3、功能实现4、开发技术简介5、系统物理架构6、系统流程图7、库表设计8、关键代码9、源码获取10、 &#x1f389;写在最后 1、前言介绍 伴随着信息技术…