交互式-辅助提取边界线

点云重建几何形状是一项常见的任务,通常由建模工程师在具有cad功能的软件中手动建模几何形状来完成。基于全自动几何提取的最先进的工作流程受到点云密度和内存限制,需要用 户进行预处理和后处理。本文提出一种交互式、用户驱动、特征辅助的从任意大小的点云进行交互式提取边缘的框架。

本文目前实现了所有功能,下面看下程序运行结果。

交互式选择种子点:

搜索临近区域:

平面分割:

交点提取:

双向生长:

终止生长:

碰到多面角点停止生长

下面,附上本人的代码,为python实现。

import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import pairwise_distances

class PointCloudProcessing:
    def __init__(self, point_cloud_path):
        self.point_cloud = o3d.io.read_point_cloud(point_cloud_path)
        self.seed_point = None
        self.picked_indices = None
    # 交互式选择点
    def pick_points(self):
        print("")
        print(
            "1) 请至少选择三个对应点,使用 [Shift + 左键单击]"
        )
        print("   按 [Shift + 右键单击] 取消点的选择")
        print("2) 选择完点后,按 'Q' 键关闭窗口")
        vis = o3d.visualization.VisualizerWithEditing()
        vis.create_window()
        vis.add_geometry(self.point_cloud)
        vis.run()  # user picks points
        vis.destroy_window()
        print("")
        picked_indices = np.asarray(vis.get_picked_points())
        if len(picked_indices) > 0:
            # Convert Python list to NumPy array and update the colors
            self.picked_indices = np.asarray(picked_indices)
            self.point_cloud.colors[self.picked_indices] = [1, 0, 0]
            self.seed_point = np.array(self.point_cloud.points)[picked_indices]
            print(self.seed_point)
        else:
            print("No points picked.")


    def extract_local_points(self,search_radius):
        [k, idx, _] = pcd_tree.search_radius_vector_3d(self.point_cloud.points[self.picked_indices],search_radius)
        np.asarray(self.point_cloud.colors)[idx[1:], :] = [0, 1, 0]
        print("Visualize the point cloud.")
        o3d.visualization.draw_geometries([self.point_cloud])
        local_points = np.asarray(self.point_cloud.points)[idx[1:], :]
        local_points = np.append(local_points, self.seed_point,axis=0)
        local_points_pc = o3d.geometry.PointCloud()
        local_points_pc.points = o3d.utility.Vector3dVector(local_points)
        # o3d.visualization.draw_geometries([local_points_pc])
        return local_points_pc


    def fit_planes(self, pcd):
        segment_models = {}  # 用于存储平面分割模型的字典
        segments = {}  # 存储分割出的点云片段的字典
        max_plane_idx = 2  # 最大平面数量
        rest = pcd  # 初始点云,用于迭代分割
        d_threshold = 0.01  # DBSCAN聚类时的距离阈值

        # 遍历每个平面进行分割
        for i in range(max_plane_idx):
            # 使用RANSAC算法进行平面分割
            colors = plt.get_cmap("tab20")(i)
            segment_models[i], inliers = rest.segment_plane(distance_threshold=2, ransac_n=5, num_iterations=1000)
            # 选择平面内的点云
            segments[i] = rest.select_by_index(inliers)

            # 使用DBSCAN进行聚类,获取每个聚类的标签
            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("最好的拟合面是:", 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.")
        # 可视化平面分割效果
        o3d.visualization.draw_geometries([segments[i] for i in range(max_plane_idx)])

        # 将 Open3D 的点云数据转换为 NumPy 数组
        points_i = np.asarray(segments[0].points)
        points_j = np.asarray(segments[1].points)

        # 计算欧式距离矩阵
        distances_matrix = pairwise_distances(points_i, points_j)

        # 找到距离小于1的点的索引
        row_indices, col_indices = np.where(distances_matrix < 6)
        # 将满足条件的点添加到最近点列表
        closest_points = np.concatenate([points_i[row_indices], points_j[col_indices]])
        # 将 closest_points 转换为 Open3D 点云对象
        point_cloud = o3d.geometry.PointCloud()
        point_cloud.points = o3d.utility.Vector3dVector(closest_points)
        o3d.io.write_point_cloud("point_cloud.pcd",point_cloud)
        return closest_points

if __name__ == "__main__":
    point_cloud_path = r'C:\Users\zhaojunzhe\Desktop\pointcloud\bottom_staircase.pcd'
    # 声明类
    processor = PointCloudProcessing(point_cloud_path)
    # 按shift+左键选取感兴趣点
    processor.pick_points()
    search_radius = 80 #设置搜索半径
    pcd_tree = o3d.geometry.KDTreeFlann(processor.point_cloud)
    # 提取感兴趣范围内点云数据
    local_pcd = processor.extract_local_points(search_radius)
    o3d.io.write_point_cloud("local_pcd.pcd",local_pcd)
    # 平面分割
    plane_params = processor.fit_planes(local_pcd)
  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值