Open3D 点云分割基础案例

Open3D 分割案例:

RANSAC(Random sample consensus)算法原理:

随机抽样一致性算法RANSAC(Random sample consensus)是一种迭代的方法来从一系列包含有离异值的数据中计算数学模型参数的方法。
RANSAC算法本质上由两步组成,不断进行循环:
从输入数据中随机选出能组成数学模型的最小数目的元素,使用这些元素计算出相应模型的参数。选出的这些元素数目是能决定模型参数的最少的。
检查所有数据中有哪些元素能符合第一步得到的模型。超过错误阈值的元素认为是离群值(outlier),小于错误阈值的元素认为是内部点(inlier)。
这个过程重复多次,选出包含点最多的模型即得到最后的结果。

RANSAC具体到空间点云中拟合平面:
1、从点云中随机选取三个点。
2、由这三个点组成一个平面。
3、计算所有其他点到该平面的距离,如果小于阈值T,就认为是处在同一个平面的点。
3、如果处在同一个平面的点超过n个,就保存下这个平面,并将处在这个平面上的点都标记为已匹配。
4、终止的条件是迭代N次后找到的平面小于n个点,或者找不到三个未标记的点。

RANSAC 总结:(参数:最少点个数MinPts,半径 R)
1:确定拟合模型
2:确定拟合该模型每次需要的点个数
3:随机选点计算模型参数
4:根据距离d计算inlier个数
5:重复随机,保留inlier个数最多的那个模型
参数:距离d,随机次数n,拟合模型

在这里插入图片描述

在这里插入图片描述

利用前面所学知识,实践分割案例:
分割如下点云,实现步骤:
1.使用 RANSAC 循环分割平面
2.使用 DBSCAN 对不规则的物体进行聚类
在这里插入图片描述

RANSAC:

import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt
# Open3D 0.16版本的 api

pcd = o3d.io.read_point_cloud("sample.ply")
# 计算法线
pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=16), fast_normal_computation=True)
pcd.paint_uniform_color([0,0,1])
# #RANSAC
[a, b, c, d], inliers = pcd.segment_plane(distance_threshold=0.01,ransac_n=3,num_iterations=1000)
print(f"平面方程: {a:.2f}x + {b:.2f}y + {c:.2f}z + {d:.2f} = 0")
inlier_cloud = pcd.select_by_index(inliers)
outlier_cloud = pcd.select_by_index(inliers, invert=True)
inlier_cloud.paint_uniform_color([1.0, 0, 0])
outlier_cloud.paint_uniform_color([0.6, 0.6, 0.6])
o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud])

在这里插入图片描述

DBSCAN:

import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt
# Open3D 0.16版本的 api

pcd = o3d.io.read_point_cloud("sample.ply")
# 计算法线
pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=16), fast_normal_computation=True)
pcd.paint_uniform_color([0,0,1])
# # DBSCAN
labels = np.array(pcd.cluster_dbscan(eps=0.05, min_points=10))
max_label = labels.max()
print(f"point cloud has {max_label + 1} clusters")

# 给不同类别赋予不同的颜色
colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
colors[labels < 0] = 0
pcd.colors = o3d.utility.Vector3dVector(colors[:, :3])
o3d.visualization.draw_geometries([pcd])

segment_models={}
segments={}
max_plane_idx=40
rest=pcd
d_threshold=0.01
for i in range(max_plane_idx):
    colors = plt.get_cmap("tab20")(i)
    segment_models[i], inliers = rest.segment_plane(distance_threshold=0.01,ransac_n=3,num_iterations=1000)
    segments[i]=rest.select_by_index(inliers)
    labels = np.array(segments[i].cluster_dbscan(eps=d_threshold*10, min_points=10))
    candidates=[len(np.where(labels==j)[0]) for j in np.unique(labels)]
    best_candidate=int(np.unique(labels)[np.where(candidates==np.max(candidates))[0]])
    print("the best candidate is: ", best_candidate)
    rest = rest.select_by_index(inliers, invert=True)+segments[i].select_by_index(list(np.where(labels!=best_candidate)[0]))
    segments[i]=segments[i].select_by_index(list(np.where(labels==best_candidate)[0]))
    segments[i].paint_uniform_color(list(colors[:3]))
    print("pass",i+1,"/",max_plane_idx,"done.")

    labels = np.array(rest.cluster_dbscan(eps=0.05, min_points=5))
    max_label = labels.max()
    print(f"point cloud has {max_label + 1} clusters")

    colors = plt.get_cmap("tab10")(labels / (max_label if max_label > 0 else 1))
    colors[labels < 0] = 0
    rest.colors = o3d.utility.Vector3dVector(colors[:, :3])

o3d.visualization.draw_geometries([segments[i] for i in range(max_plane_idx)]+[rest])

运行效果如下:

在这里插入图片描述

在这里插入图片描述

PCL Ransac拟合平面

代码演示:

import open3d as o3d

pcd = o3d.io.read_point_cloud("1.ply")
print(pcd)

distance_threshold = 0.2    # 内点到平面模型的最大距离
ransac_n = 3                # 用于拟合平面的采样点数
num_iterations = 1000       # 最大迭代次数

# 返回模型系数plane_model和内点索引inliers,并赋值
plane_model, inliers = pcd.segment_plane(distance_threshold, ransac_n, num_iterations)

# 输出平面方程
[a, b, c, d] = plane_model
print(f"Plane equation: {a:.2f}x + {b:.2f}y + {c:.2f}z + {d:.2f} = 0")
# 平面内点点云
inlier_cloud = pcd.select_by_index(inliers)
inlier_cloud.paint_uniform_color([0, 0, 1.0])
print(inlier_cloud)
# 平面外点点云
outlier_cloud = pcd.select_by_index(inliers, invert=True)
outlier_cloud.paint_uniform_color([1.0, 0, 0])
print(outlier_cloud)
# 可视化平面分割结果
o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud])

在这里插入图片描述
在这里插入图片描述
密度聚类:
Open3D中的cluster_dbscan实现密度聚类。需要两个参数:
1.eps为同一簇内的最大点间距,
2.min_points定义有效聚类的最小点数。
函数返回标签label,其中label = -1表示噪声

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

# 读取点云s
pcd = o3d.io.read_point_cloud("4.ply")
print(pcd)
# 密度聚类
eps = 1.5  # 同一聚类中最大点间距
min_points = 50  # 有效聚类的最小点数
with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
    labels = np.array(pcd.cluster_dbscan(eps, min_points, print_progress=True))
max_label = labels.max()

print(f"point cloud has {max_label + 1} clusters")  # label = -1 为噪声,因此总聚类个数为 max_label + 1

colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
colors[labels < 0] = 0  # labels = -1 的簇为噪声,以黑色显示
pcd.colors = o3d.utility.Vector3dVector(colors[:, :3])
o3d.visualization.draw_geometries([pcd])

在这里插入图片描述
代码难点解读,请看我下一篇文章,链接:
代码解析链接https://blog.csdn.net/qq_52040083/article/details/134435780?spm=1001.2014.3001.5502

代码函数语法难点:

np.max 与 np.maximum
>> np.max([-2, -1, 0, 1, 2])
2
>> np.maximum([-2, -1, 0, 1, 2], 0)
array([0, 0, 0, 1, 2])

当然 np.maximum 接受的两个参数,也可以大小一致

或者更为准确地说,第二个参数只是一个单独的值时,其实是用到了维度的 broadcast 机制;

# 当然 np.maximum 接受的两个参数,也可以大小一致
# 或者更为准确地说,第二个参数只是一个单独的值时,其实是用到了维度的 broadcast 机制;

Broadcast机制(还不够了解,CSDN链接解析)
大神总结https://blog.csdn.net/qq_38683460/article/details/126331052

np.unique( )的用法
该函数是去除数组中的重复数字,并进行排序之后输出。

拓展:
np.array(png),这个函数处理图片之后得到的结果是什么?
可以得到图像中存在的灰度值(或者像素值),然后分别统计图片里这些灰度值出现的个数,就可以得到灰度分布直方图了

numpy.where() 有两种用法:
网址链接:
大神链接https://www.cnblogs.com/massquantity/p/8908859.html

numpy网址https://numpy.org/doc/stable/reference/generated/numpy.where.html

np.where(condition, x, y)
满足条件(condition),输出x,不满足输出y。
np.where(condition)
只有条件 (condition),没有x和y,则输出满足条件 (即非0) 元素的坐标 (等价于numpy.nonzero)。这里的坐标以tuple的形式给出,通常原数组有多少维,输出的tuple中就包含几个数组,分别对应符合条件元素的各维坐标。

列表生成式:
链接:
大神链接https://www.liaoxuefeng.com/wiki/1016959663602400/1017317609699776

即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
可以用list(range(1, 11))
### 3D点云分割技术概述 3D点云分割是一种用于处理三维空间数据的技术,旨在将点云划分为具有特定语义意义的不同部分。这种方法广泛应用于机器人视觉、自动驾驶以及增强现实等领域。 #### 特征描述子与机器学习方法 一种常见的方法是从点云数据中提取3D特征并利用机器学习技术对其进行分类[^1]。此方法通过构建特征描述子来捕捉点云的局部特性,并将其输入至训练好的模型中完成类别预测。相比仅依靠几何推理的方式,该方法能够更好地应对复杂场景下的挑战,例如噪声干扰、密度分布不均以及遮挡等问题。然而,这类方法的一个主要缺点在于计算效率较低,同时其性能高度依赖于前期特征提取的质量。 #### 基于深度学习的解决方案 近年来,随着深度学习的发展,许多研究者提出了结合神经网络架构实现更高效精准的点云分割方案。例如,《SceneEncoder》一文中介绍了一种名为“可学习场景描述符”的框架设计思路[^2]。它不仅考虑到了单个点的信息,还引入全局上下文感知机制以提升整体表现力。这种端到端的学习模式减少了手工定义参数的需求,从而简化了开发流程。 #### 区域生长算法详解 另一种经典的传统分割手段即为区域生长法。具体而言,它是从选定的一组初始种子点出发,逐步扩展相邻符合条件的新成员直至达到边界限制为止[^3]。整个过程中涉及到的关键因素包括但不限于距离阈值设定、角度一致性检验等准则制定。尽管其实现较为直观简单,但在面对大规模或者结构复杂的实际案例时可能会暴露出收敛速度慢以及易受异常值影响等诸多不足之处。 ```python import numpy as np from open3d.cpu.pybind.geometry import PointCloud, Vector3dVector def region_growing_segmentation(point_cloud_data, seed_points_indices, max_distance=0.05): """ Perform basic region growing segmentation on a given point cloud. Parameters: point_cloud_data (numpy.ndarray): Input array representing the point cloud. seed_points_indices (list[int]): Indices of points to start regions from. max_distance (float): Maximum distance between two connected points within same region. Returns: list[list[int]]: List containing lists with indices belonging each segmented area respectively. """ # Convert input data into Open3D format pcd = PointCloud() pcd.points = Vector3dVector(point_cloud_data) visited_flags = set() # Track already processed nodes during traversal result_regions = [] # Store final output groups here def grow_region(current_seed_index): queue = [current_seed_index] while len(queue)>0: current_point_idx = queue.pop(0) if not current_point_idx in visited_flags: neighbors = find_neighbors_within_radius(pcd,current_point_idx,max_distance=max_distance) valid_neighbor_ids=[n for n in neighbors if check_growth_condition(n)] queue.extend(valid_neighbor_ids) visited_flags.add(current_point_idx) for sp_i in seed_points_indices: new_group=[] grow_region(sp_i,new_group) result_regions.append(new_group) return result_regions # Example usage demonstrating how function works step-by-step omitted due brevity constraints... ``` 上述代码片段展示了如何借助Python库`open3d`执行基础版本的区域增长型分割操作。值得注意的是,这只是一个非常简化的例子;真实世界应用往往需要更加精细调整各项超参配置才能获得满意效果。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值